Reflection & Observability API
Relevant source files
The following files were used as context for generating this wiki page:
The Reflection & Observability API in sidekiq-unique-jobs provides a comprehensive hook system for monitoring lock lifecycle events without altering the core middleware behavior. This system allows developers to gather metrics, implement custom logging, or trigger external alerts when jobs are locked, unlocked, or when conflicts and timeouts occur.
The API is centralized through the SidekiqUniqueJobs.reflect method, which yields a configuration object to define callbacks for specific internal events. This replaced the legacy changelog system in version 9.0 to provide a more performant and flexible way to observe the state of unique locks within Redis.
Sources: README.md:209-215, UPGRADING.md:5-9, lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb:339-354
Architecture and Components
The reflection system is built on a decoupled architecture consisting of a central registry (Reflections), a mixin for internal classes (Reflectable), and a public configuration interface.
Reflection Registry
The SidekiqUniqueJobs::Reflections class serves as the storage for all configured blocks. It uses a dispatch method to execute the registered callbacks when an event is triggered by the gem's internal logic.
Reflectable Mixin
Internal components such as Locksmith or the Middleware classes include the SidekiqUniqueJobs::Reflectable module. This module provides a convenience method reflect(reflection, *args) which proxies calls to the global reflections instance.
Sources: lib/sidekiq_unique_jobs/reflectable.rb:7-24
Event Reference
The following table summarizes the primary reflection points available for observability:
| Event | Description | Data Provided |
|---|---|---|
locked | Triggered when a lock is successfully acquired. | item (Job Hash) |
unlocked | Triggered when a lock is successfully released. | item (Job Hash) |
duplicate | Triggered when a job is identified as a duplicate and skipped. | item (Job Hash) |
lock_failed | Triggered when lock acquisition fails (e.g., conflict). | item (Job Hash) |
timeout | Triggered when the lock acquisition times out. | item (Job Hash) |
error | Triggered for general internal errors. | item, exception |
execution_failed | Triggered when job execution raises an error. | item, exception |
unlock_failed | Triggered when a lock release operation fails. | item (Job Hash) |
rescheduled | Triggered when a job is rescheduled due to conflict. | item (Job Hash) |
Sources: lib/sidekiq_unique_jobs/reflections.rb:14-53, UPGRADING.md:14-93, spec/sidekiq_unique_jobs/reflections_spec.rb:25-85
Usage and Configuration
Configuration is typically handled in a Sidekiq initializer. Developers can choose to implement only the reflections they are interested in, such as failures for alerting or successes for metrics collection.
SidekiqUniqueJobs.reflect do |on|
on.locked { |item| Metrics.increment("jobs.locked", tags: [item['class']]) }
on.lock_failed { |item| logger.warn("Lock failed for #{item['jid']}") }
on.timeout { |item| Airbrake.notify("Lock timeout for job #{item['class']}") }
end
Sources: README.md:217-224, UPGRADING.md:11-13
Context-Aware Logging
The observability API integrates with the SidekiqUniqueJobs::Logging module to provide structured log output. This module handles different Sidekiq versions (supporting Sidekiq::Context in newer versions and Sidekiq::Logging in older ones) to ensure log entries include relevant job metadata such as jid, queue, and lock_digest.
Metric Collection
The gem includes a specific LockMetrics class that utilizes the reflection-like pattern to track time spent in various phases of the lock lifecycle. It specifically tracks lock_time (acquisition) and unlock_time (release).
Key methods in SidekiqUniqueJobs::LockMetrics:
instrument(name, &block): Wraps a block of code to measure execution time.report_metrics: Placeholder for sending metrics to backends (e.g., StatsD).
Sources: lib/sidekiq_unique_jobs/lock_metrics.rb:9-35
Implementation Details
Deprecation Handling
The Reflection API includes a mechanism to warn developers when they use deprecated reflection points. The SidekiqUniqueJobs::Reflections::DEPRECATIONS constant defines mappings from old reflection names to new ones along with the version in which the old name will be removed.
Sources: lib/sidekiq_unique_jobs/reflections.rb:64-70, spec/sidekiq_unique_jobs/reflections_spec.rb:88-106
Dispatch Logic
The dispatch method handles the actual invocation. It checks if a block is registered for the given reflection type and yields the provided items (typically the job hash and optionally an exception) to that block.
Sources: lib/sidekiq_unique_jobs/reflections.rb:72-87
The Reflection & Observability API provides the necessary primitives to build robust monitoring around Sidekiq job uniqueness, allowing for precise tracking of Redis lock efficiency and conflict rates without introducing side effects into the job processing flow.