Reference

Worker options

Every per-worker key you can pass to sidekiq_options, plus the lock-type and conflict-strategy symbols they accept.

sidekiq_options keys#

Set these per worker; only lock is required.

Uniqueness is configured on the worker with sidekiq_options. Only lock: is required — it names the lock type and turns uniqueness on. Everything else tunes how the lock is keyed, how long it lives, and what happens when a duplicate loses the race. Locks in v9 are non-blocking: a contended job never waits — it fails its one attempt and the conflict strategy fires immediately.

OptionTypeDefaultDescription
lockSymbolThe lock type. Required to enable uniqueness. See the lock-type table below.
lock_ttlInteger (seconds)nilHow long the lock lives in Redis, measured from when it is created — not from when the job finishes.
lock_timeoutInteger (seconds)0Parsed and stored in lock metadata, but inert for acquisition in v9's non-blocking model — it does not make a job wait. A contended lock fails its single attempt and the conflict strategy runs immediately.
lock_limitInteger1How many concurrent holders of the same digest are allowed before a job is treated as a duplicate.
on_conflictSymbol or HashnilWhat to do with a duplicate. A single symbol, or {client:, server:} to split the two sides. See the strategy table below.
lock_args_methodSymbol or ProcnilSelects which arguments matter for uniqueness. A symbol naming a class method, or a lambda; returns the subset of args to key on.
unique_across_queuesBooleanfalseIgnore the queue when computing the digest, so the same args on any queue count as a duplicate.
unique_across_workersBooleanfalseIgnore the worker class when computing the digest, so different workers with the same args count as duplicates.
lock_infoBooleanfalseStore extra debugging metadata about the lock (who, when, which arguments) for inspection in the Web UI.
lock_prefixString"uniquejobs"Override the Redis key prefix for this worker's locks.
Any option omitted here falls back to its global default. Set those defaults once in your initializer — see Configuration reference.

Lock types and their aliases#

Pass any alias to lock: — they map to the same behavior.

There are five lock types. Each has aliases that read differently but behave identically — use whichever is clearest, though the canonical name (the first in each row) is the one this documentation uses. See Choosing a lock type for when to reach for each.

CanonicalAliasesHolds the lock
:until_executed:until_completed, :until_performed, :until_processed, :until_successfully_completedFrom enqueue until the job finishes
:until_executing:while_enqueuedFrom enqueue until the job starts running
:until_expiredFrom enqueue until the TTL expires
:while_executing:around_perform, :while_busy, :while_workingOnly while the job runs (prevents concurrent execution)
:while_executing_rejectLike :while_executing, but forces on_conflict: :reject on the server
:until_and_while_executingFrom enqueue until start, then again for the duration of the run

on_conflict strategies#

What happens to a job that loses the race for a lock.

When a duplicate can't acquire the lock, the conflict strategy decides its fate. Pass one symbol, or a { client:, server: } hash to use different strategies on the enqueue side and the execution side.

StrategyBehavior
:logLog the conflict and discard the duplicate. This is the effective default.
:raiseRaise so Sidekiq retries the job later.
:rejectPush the duplicate to the Dead set.
:replaceDelete the existing job and lock, then enqueue the new one.
:rescheduleRe-enqueue the duplicate to run later.
A while_executing conflict happens during execution, so its on_conflict is a server-side strategy. Split the two sides when the client and server should behave differently, e.g. on_conflict: { client: :log, server: :reschedule }.

See Conflict resolution for worked examples of each strategy.

A worker using many options at once#

Nothing about these options is mutually exclusive. A single worker can pin the lock type, cap the lock's lifetime, filter which arguments matter, and split its conflict behavior across client and server:

class GenerateReportJob
  include Sidekiq::Job

  sidekiq_options lock: :until_and_while_executing,
                  lock_ttl: 3_600,
                  lock_args_method: :unique_args,
                  unique_across_queues: true,
                  lock_info: true,
                  on_conflict: { client: :log, server: :reschedule }

  # Only the account_id decides uniqueness; the requested_at
  # timestamp is transient and must be ignored.
  def self.unique_args(args)
    [args.first]
  end

  def perform(account_id, requested_at)
    # One report per account_id: unique in the queue, and serialized
    # so two never render concurrently.
  end
end

Here the lock is held from enqueue through the end of the run, capped at one hour. A duplicate enqueue is logged and dropped immediately — locks are non-blocking, so nothing waits — while a duplicate that reaches the server is rescheduled. Because lock_args_method keys only on account_id, two calls with different requested_at values are still the same job.