Conflict Strategies
Relevant source files
The following files were used as context for generating this wiki page:
- lib/sidekiq_unique_jobs/on_conflict.rb
- lib/sidekiq_unique_jobs/on_conflict/strategy.rb
- lib/sidekiq_unique_jobs/on_conflict/reschedule.rb
- lib/sidekiq_unique_jobs/on_conflict/replace.rb
- lib/sidekiq_unique_jobs/on_conflict/null_strategy.rb
- lib/sidekiq_unique_jobs/config.rb
- spec/sidekiq_unique_jobs/on_conflict/reject_spec.rb
Conflict Strategies in sidekiq-unique-jobs provide mechanisms for resolving lock contention when a job is being enqueued or executed. When the system detects that a unique lock is already held for a specific digest, the designated conflict strategy dictates the subsequent action, such as logging the event, rescheduling the job, or replacing the existing lock.
The strategy system is architected around a base abstract class, SidekiqUniqueJobs::OnConflict::Strategy, which defines the interface for all resolution behaviors. Strategies can be configured globally or on a per-worker basis to handle different scenarios for client-side (enqueuing) and server-side (executing) conflicts.
Sources: lib/sidekiq_unique_jobs/on_conflict.rb:10-14, CLAUDE.md:73-81
Core Architecture
The OnConflict module acts as a factory for retrieving conflict resolutions. It uses the SidekiqUniqueJobs.strategies configuration to map symbols (e.g., :log, :replace) to their respective implementation classes. If no strategy is found or provided, it defaults to the NullStrategy.
The diagram above shows the inheritance structure where specific resolution behaviors inherit from the abstract Strategy class.
Sources: lib/sidekiq_unique_jobs/on_conflict/strategy.rb:9-52, lib/sidekiq_unique_jobs/on_conflict.rb:29-45
Strategy Resolution Process
When a conflict occurs, the system attempts to find a strategy based on the job's configuration. The following sequence illustrates how a strategy is identified and executed:
Available Strategies
The gem provides several built-in strategies to handle duplicate jobs:
| Strategy | Key | Description |
|---|---|---|
| Log | :log | Logs the conflict event and skips the job without further action. |
| Raise | :raise | Raises a SidekiqUniqueJobs::Conflict error, typically used to trigger Sidekiq retries. |
| Reject | :reject | Sends the conflicting job directly to the Sidekiq Dead Set. |
| Replace | :replace | Deletes the existing job/lock and allows the new job to proceed. |
| Reschedule | :reschedule | Re-queues the job to be performed after a specific delay. |
| Null | nil | A NOOP strategy that performs no action. |
Sources: lib/sidekiq_unique_jobs/config.rb:92-98, lib/sidekiq_unique_jobs/on_conflict/null_strategy.rb:9-16, CLAUDE.md:73-81
Replace Strategy
The Replace strategy is designed to favor the incoming job by removing the existing one. It attempts to delete the job from the queue, schedule, or retry sets in Redis using a Lua script.
Reschedule Strategy
The Reschedule strategy re-enqueues the job with a RESCHEDULED flag. This flag is critical as it instructs the middleware to skip uniqueness checks for the new instance, preventing infinite recursion if the original lock is still held.
- Default Delay: 5 seconds (configurable via
schedule_inoption). - Flagging: Sets
item['rescheduled'] = true.
Sources: lib/sidekiq_unique_jobs/on_conflict/reschedule.rb:25-45
Reject Strategy
This strategy moves the conflicting job to the Sidekiq DeadSet. It handles version-specific logic for Sidekiq's kill method, checking if it supports optional keyword arguments like notify_failure.
Sources: spec/sidekiq_unique_jobs/on_conflict/reject_spec.rb:45-77
Configuration
Conflict strategies can be defined in three layers:
- Global Configuration: Set via
SidekiqUniqueJobs.config.on_conflict. - Worker-level (Unified): Set via
sidekiq_options on_conflict: :strategy_name. - Worker-level (Split): Set via a hash to differentiate between
client(enqueue) andserver(execute) conflicts.
# Example of split configuration in a worker
sidekiq_options lock: :until_executed,
on_conflict: {
client: :log,
server: :reschedule
}
Sources: spec/sidekiq_unique_jobs/lock_config_spec.rb:149-195, spec/sidekiq_unique_jobs/job_spec.rb:36-50
Implementation Details
Strategy Initialization
Every strategy is initialized with the Sidekiq job hash (item) and an optional redis_pool.
Sources: lib/sidekiq_unique_jobs/on_conflict/strategy.rb:30-34
Custom Strategies
Users can add custom conflict resolutions by inheriting from SidekiqUniqueJobs::OnConflict::Strategy and registering them via the configuration:
SidekiqUniqueJobs.configure do |config|
config.add_strategy :my_strategy, CustomStrategies::MyStrategy
end
Sources: lib/sidekiq_unique_jobs/config.rb:255-263
Summary
Conflict Strategies are a vital component of the sidekiq-unique-jobs ecosystem, providing the flexibility needed to handle duplicate jobs based on specific business logic. Whether by simply logging conflicts or by actively replacing or rescheduling jobs, these strategies ensure that the uniqueness constraints are maintained without causing unintended job loss or system deadlocks.