Redis Entity Wrappers
Relevant source files
The following files were used as context for generating this wiki page:
The Redis Entity Wrappers in sidekiq-unique-jobs provide an object-oriented interface for interacting with various Redis data structures. By wrapping low-level Redis commands into dedicated classes, the gem ensures consistent handling of job metadata, lock digests, and expiration logic across the system. These wrappers abstract the complexities of the underlying redis-client or Sidekiq connection pool, offering a high-level API for data persistence and retrieval.
These entities serve as the primary layer for managing the lifecycle of unique job digests and lock information stored in Redis. They integrate core gem functionalities such as logging, JSON serialization, and Lua script execution to maintain atomic operations during lock acquisition and release.
Sources: lib/sidekiq_unique_jobs/redis/entity.rb, CLAUDE.md:89-95
Core Architecture and Inheritance
All Redis wrappers inherit from a common base class, SidekiqUniqueJobs::Redis::Entity. This base class provides the fundamental infrastructure required for Redis communication, including access to the connection pool and utility mixins.
Class Hierarchy
The following diagram illustrates the relationship between the base Entity and its specialized data structure subclasses:
The base Entity class includes several critical mixins that provide shared functionality for all Redis operations.
Sources: lib/sidekiq_unique_jobs/redis/entity.rb:10-33
Shared Mixins
| Mixin | Purpose |
|---|---|
SidekiqUniqueJobs::Logging | Provides structured logging for Redis operations. |
SidekiqUniqueJobs::Script::Caller | Enables the execution of Lua scripts for atomic operations. |
SidekiqUniqueJobs::JSON | Handles serialization and deserialization of job data. |
SidekiqUniqueJobs::Timing | Provides helpers for time-based calculations (e.g., now_f). |
Sources: lib/sidekiq_unique_jobs/redis/entity.rb:14-25, lib/sidekiq_unique_jobs/script/caller.rb:11-15
Specialized Redis Entities
Redis::Hash
The Hash wrapper manages Redis Hash structures, primarily used for storing lock metadata (e.g., job IDs and timestamps). It provides methods to retrieve entries with or without their values.
- Key Functions:
entries(with_values: true): Returns a Hash of all field-value pairs or an Array of keys ifwith_valuesis false.count: Returns the number of fields in the hash usingHLEN.
Sources: lib/sidekiq_unique_jobs/redis/hash.rb, spec/sidekiq_unique_jobs/redis/hash_spec.rb:13-34
Redis::SortedSet
The SortedSet wrapper is critical for managing ordered data, such as expiring digests or job rankings. In version 9.x, it is used for the uniquejobs:digests set where scores represent expiry times.
- Key Functions:
add(values): Adds members with scores. If a single value is provided, it uses the current time (now_f) as the score.byscore(min, max, ...): Retrieves members within a specific score range usingZRANGE.clear: Efficiently removes all entries usingZREMRANGEBYRANK.score(member): Retrieves the score for a specific member viaZSCORE.
Sources: lib/sidekiq_unique_jobs/redis/sorted_set.rb:11-96, README.md:126-130
Redis::String
The String wrapper handles simple key-value pairs. It is frequently used for individual digest keys during the locking process.
- Key Functions:
value: Retrieves the string value stored at the key.del: Deletes the key and returns the count of deleted items.
Sources: spec/sidekiq_unique_jobs/redis/string_spec.rb:12-46
Redis Communication Flow
All entities interact with Redis through a connection block, ensuring thread safety and proper connection pooling via Sidekiq's infrastructure. The Script::Caller mixin enhances this by allowing entities to execute complex logic atomically on the Redis server.
The call_script method automatically appends global context to every Lua call, including the current timestamp (now_f), debug status, and the current Redis version.
Sources: lib/sidekiq_unique_jobs/script/caller.rb:43-55, lib/sidekiq_unique_jobs/redis/entity.rb:45-56
Key Methods and Properties
The following table summarizes the common API available to all Redis Entity objects:
| Method | Return Type | Description |
|---|---|---|
key | String | Returns the raw Redis key string. |
exist? | Boolean | Checks for the existence of the key using EXISTS. |
ttl | Integer | Returns the time-to-live in seconds. |
pttl | Integer | Returns the time-to-live in milliseconds. |
expires? | Boolean | Returns true if the key has an expiration set. |
count | Integer | Returns the size of the collection (default 0 in base class). |
Sources: lib/sidekiq_unique_jobs/redis/entity.rb:39-105
Implementation Details
Boolean Existence Check
The exist? implementation includes compatibility logic for different Redis client versions, handling both boolean and integer returns from the exists command.
def exist?
redis do |conn|
value = conn.respond_to?(:exists?) ? conn.exists?(key) : conn.exists(key)
return value if boolean?(value)
value.to_i.positive?
end
end
Sources: lib/sidekiq_unique_jobs/redis/entity.rb:50-64
Script Argument Normalization
The Script::Caller mixin ensures that arguments passed to Redis Lua scripts are normalized. Specifically, it converts Ruby true/false/nil values into integers (1/0) to ensure compatibility with Lua's type system.
Sources: lib/sidekiq_unique_jobs/script/caller.rb:147-157
Summary
Redis Entity Wrappers provide the foundational abstraction layer for data persistence in sidekiq-unique-jobs. By utilizing a structured inheritance model and shared mixins, the gem maintains atomic operations and consistent metadata handling across diverse Redis data types like Hashes, Strings, and Sorted Sets. This architecture allows the gem to perform complex locking logic while shielding the rest of the codebase from the specifics of Redis protocol and connection management.