Lock Types
Relevant source files
The following files were used as context for generating this wiki page:
Lock Types in sidekiq-unique-jobs define the strategy and lifecycle of a job's uniqueness. They determine at which point in the Sidekiq job lifecycle (enqueuing or execution) a lock is acquired and when it is released. This mechanism ensures that duplicate jobs, as defined by their unique digest, do not overlap in ways that violate business logic or system constraints.
Sources: README.md:47-55, CLAUDE.md:37-45
Overview of Lock Strategies
The system categorizes locks primarily into client-side locks, which prevent duplicate enqueuing, and server-side locks, which prevent duplicate execution.
Available Lock Types
| Type | Acquisition Point | Release Point | Primary Purpose |
|---|---|---|---|
:until_executing | Enqueue (Client) | Before performance starts | Prevent duplicate enqueuing only. |
:until_executed | Enqueue (Client) | After performance completes | Prevent duplicates until the job finishes. |
:until_expired | Enqueue (Client) | TTL Expiry | Time-based uniqueness (e.g., daily jobs). |
:while_executing | Perform (Server) | After performance completes | Prevent concurrent execution of the same job. |
:until_and_while_executing | Enqueue + Perform | After performance completes | Full lifecycle protection. |
Sources: README.md:47-55, CLAUDE.md:37-45
Architecture and Components
The lock system is built on a hierarchy of classes that manage configuration, acquisition logic, and Redis interactions.
Lock Configuration (LockConfig)
The LockConfig class gathers all configuration for a specific lock from the worker's sidekiq_options. It handles parameters such as lock_limit, lock_timeout, and lock_ttl.
Sources: lib/sidekiq_unique_jobs/lock_config.rb:11-40
Lock Management (Locksmith)
Locksmith is the central manager that interfaces with Redis via Lua scripts. It is responsible for the actual lock, unlock, and execute operations. It uses a Key object (derived from the lock_digest) to identify the lock in Redis.
Sources: lib/sidekiq_unique_jobs/locksmith.rb:8-50
Base Lock Logic (BaseLock)
All specific lock implementations inherit from BaseLock. This abstract class provides the foundation for validating options and interacting with the Locksmith. It also manages conflict strategies when a lock cannot be acquired.
Sources: lib/sidekiq_unique_jobs/lock/base_lock.rb:10-50
Lock Lifecycle Diagram
The following diagram illustrates how the Sidekiq middleware interacts with the lock system during a job's journey.
The diagram shows the dual-gate approach where locks can be checked at the client (enqueuing) and server (executing) stages.
Sources: lib/sidekiq_unique_jobs/lock/base_lock.rb:55-80, CLAUDE.md:48-60
Specific Lock Behaviors
Client-Side Locks
Client-side locks are primarily managed by SidekiqUniqueJobs::Middleware::Client. They prevent a job from even entering the Redis queue if a lock with the same digest already exists.
until_executed: This is a common strategy where the lock is held from the moment of enqueuing until the worker successfully finishes theperformmethod.until_expired: This lock does not have a manual unlock point; it relies solely on the Redis TTL (Time To Live). Note thatafter_unlockcallbacks are never called for this type.
Sources: CLAUDE.md:38-42, README.md:47-55
Server-Side Locks
Server-side locks are managed by SidekiqUniqueJobs::Middleware::Server. These do not prevent multiple jobs from being enqueued; they only ensure that the perform method does not run concurrently for the same digest.
while_executing: Only prevents concurrent execution. If multiple jobs are in the queue with the same digest, they will wait for each other (iflock_timeoutallows) or trigger a conflict strategy.
Sources: CLAUDE.md:44-46, README.md:47-55
Data Structures in Redis
Locks in version 9.x have been simplified to use fewer Redis keys.
| Component | Redis Type | Description |
|---|---|---|
digest:LOCKED | Hash | Stores metadata (JID, worker, time, type) for active locks. |
uniquejobs:digests | Sorted Set (ZSET) | Tracks all active digests for cleanup and auditing. |
Sources: lib/sidekiq_unique_jobs/lock.rb:58-85, README.md:126-129
Lock Metadata Storage
When a job is locked, metadata is stored as JSON within the LOCKED hash. This information is used for the Web UI and debugging.
def lock(job_id, lock_info = {}, score = nil)
score ||= now_f
metadata = dump_json(lock_info.merge("time" => @created_at || now_f))
redis do |conn|
conn.multi do |pipeline|
pipeline.call("HSET", key.locked, job_id, metadata)
pipeline.call("ZADD", key.digests, score.to_s, key.digest)
end
end
end
Sources: lib/sidekiq_unique_jobs/lock.rb:58-71
Conclusion
Lock types provide the essential flexibility required to handle various uniqueness requirements in distributed background processing. By choosing between client-side, server-side, or combined locks, developers can precisely control the concurrency and duplication constraints of their Sidekiq workers.