package store import ( "context" "database/sql" "fmt" "time" ) type Locks struct { DB *sql.DB TTLMinutes int } func (s *Locks) Acquire(ctx context.Context, hostID, operationID int64) error { s.cleanExpired(ctx) expiresAt := time.Now().UTC().Add(time.Duration(s.TTLMinutes) * time.Minute).Format(time.RFC3339) _, err := s.DB.ExecContext(ctx, ` INSERT INTO operation_locks(host_id, operation_id, expires_at) VALUES(?,?,?) `, hostID, operationID, expiresAt) if err != nil { return fmt.Errorf("acquire lock: %w", err) } return nil } func (s *Locks) Release(ctx context.Context, hostID int64) error { _, err := s.DB.ExecContext(ctx, `DELETE FROM operation_locks WHERE host_id = ?`, hostID) return err } func (s *Locks) IsLocked(ctx context.Context, hostID int64) (bool, error) { s.cleanExpired(ctx) var count int err := s.DB.QueryRowContext(ctx, `SELECT COUNT(1) FROM operation_locks WHERE host_id = ?`, hostID).Scan(&count) if err != nil { return false, fmt.Errorf("check lock: %w", err) } return count > 0, nil } func (s *Locks) cleanExpired(ctx context.Context) { now := time.Now().UTC().Format(time.RFC3339) _, _ = s.DB.ExecContext(ctx, `DELETE FROM operation_locks WHERE expires_at < ?`, now) }