55 lines
1.9 KiB
Go
55 lines
1.9 KiB
Go
package creator
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"time"
|
|
)
|
|
|
|
// 同步互斥租约:与作品/评论采集共用 creator_collection_checkpoint(统一租约模式),
|
|
// collection_kind='sync',窗口列填 now() 占位(同步租约不跟踪采集窗口)。
|
|
func (s *Store) ClaimSourceSync(ctx context.Context, sourceType, sourceID string) (string, error) {
|
|
if sourceType != SourceOwned && sourceType != SourceCompetitor || sourceID == "" {
|
|
return "", ErrInvalid
|
|
}
|
|
token := newID("lease")
|
|
now := time.Now().UTC()
|
|
var claimed string
|
|
err := s.db.QueryRowContext(ctx, `
|
|
INSERT INTO creator_collection_checkpoint
|
|
(source_type, source_id, collection_kind, cursor, window_start, window_end, status, lease_token, lease_until, last_error)
|
|
VALUES ($1, $2, 'sync', '', $3, $3, 'running', $4, $3::timestamptz + interval '10 minutes', '')
|
|
ON CONFLICT (source_type, source_id, collection_kind) DO UPDATE SET
|
|
status = 'running', lease_token = EXCLUDED.lease_token, lease_until = EXCLUDED.lease_until
|
|
WHERE creator_collection_checkpoint.lease_until IS NULL
|
|
OR creator_collection_checkpoint.lease_until <= now()
|
|
RETURNING lease_token`, sourceType, sourceID, now, token).Scan(&claimed)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return "", ErrConflict
|
|
}
|
|
if err != nil {
|
|
return "", databaseError(err)
|
|
}
|
|
return claimed, nil
|
|
}
|
|
|
|
func (s *Store) ReleaseSourceSync(ctx context.Context, sourceType, sourceID, token string) error {
|
|
if sourceType != SourceOwned && sourceType != SourceCompetitor || sourceID == "" || token == "" {
|
|
return ErrInvalid
|
|
}
|
|
result, err := s.db.ExecContext(ctx, `
|
|
DELETE FROM creator_collection_checkpoint
|
|
WHERE source_type = $1 AND source_id = $2 AND collection_kind = 'sync' AND lease_token = $3`,
|
|
sourceType, sourceID, token)
|
|
if err != nil {
|
|
return databaseError(err)
|
|
}
|
|
if rows, err := result.RowsAffected(); err != nil {
|
|
return err
|
|
} else if rows != 1 {
|
|
return ErrConflict
|
|
}
|
|
return nil
|
|
}
|