Class: SidekiqUniqueJobs::Config

Inherits:
ThreadSafeConfig
  • Object
show all
Defined in:
lib/sidekiq_unique_jobs/config.rb

Overview

Shared class for dealing with gem configuration

Author:

  • Mauro Berlanda <mauro.berlanda@gmail.com>

Constant Summary collapse

LOCKS_WHILE_ENQUEUED =

Returns Hash<Symbol, SidekiqUniqueJobs::Lock::BaseLock] all available queued locks.

Returns:

{
  until_executing: SidekiqUniqueJobs::Lock::UntilExecuting,
  while_enqueued: SidekiqUniqueJobs::Lock::UntilExecuting,
}.freeze
LOCKS_FROM_PUSH_TO_PROCESSED =

Returns Hash<Symbol, SidekiqUniqueJobs::Lock::BaseLock] all available fulltime locks.

Returns:

{
  until_completed: SidekiqUniqueJobs::Lock::UntilExecuted,
  until_executed: SidekiqUniqueJobs::Lock::UntilExecuted,
  until_performed: SidekiqUniqueJobs::Lock::UntilExecuted,
  until_processed: SidekiqUniqueJobs::Lock::UntilExecuted,
  until_and_while_executing: SidekiqUniqueJobs::Lock::UntilAndWhileExecuting,
  until_successfully_completed: SidekiqUniqueJobs::Lock::UntilExecuted,
}.freeze
LOCKS_WITHOUT_UNLOCK =

Returns Hash<Symbol, SidekiqUniqueJobs::Lock::BaseLock] all available locks without unlock.

Returns:

{
  until_expired: SidekiqUniqueJobs::Lock::UntilExpired,
}.freeze
LOCKS_WHEN_BUSY =

Returns Hash<Symbol, SidekiqUniqueJobs::Lock::BaseLock] all available runtime/client locks.

Returns:

{
  around_perform: SidekiqUniqueJobs::Lock::WhileExecuting,
  while_busy: SidekiqUniqueJobs::Lock::WhileExecuting,
  while_executing: SidekiqUniqueJobs::Lock::WhileExecuting,
  while_working: SidekiqUniqueJobs::Lock::WhileExecuting,
  while_executing_reject: SidekiqUniqueJobs::Lock::WhileExecutingReject,
}.freeze
LOCKS =

Returns Hash<Symbol, SidekiqUniqueJobs::Lock::BaseLock] all available default locks.

Returns:

LOCKS_WHEN_BUSY.dup
.merge(LOCKS_WHILE_ENQUEUED.dup)
.merge(LOCKS_WITHOUT_UNLOCK.dup)
.merge(LOCKS_FROM_PUSH_TO_PROCESSED.dup)
.freeze
STRATEGIES =

Returns Hash<Symbol, SidekiqUniqueJobs::OnConflict::Strategy] all available default strategies.

Returns:

{
  log: SidekiqUniqueJobs::OnConflict::Log,
  raise: SidekiqUniqueJobs::OnConflict::Raise,
  reject: SidekiqUniqueJobs::OnConflict::Reject,
  replace: SidekiqUniqueJobs::OnConflict::Replace,
  reschedule: SidekiqUniqueJobs::OnConflict::Reschedule,
}.freeze
PREFIX =

Returns by default we use this prefix.

Returns:

  • ('uniquejobs')

    by default we use this prefix

"uniquejobs"
LOCK_TIMEOUT =

Returns by default don’t wait for locks.

Returns:

  • (0)

    by default don’t wait for locks

0
LOCK_TTL =

Returns:

  • (nil)
nil
LOGGER_ENABLED =

Returns by default false (don’t disable logger).

Returns:

  • (true, false)

    by default false (don’t disable logger)

true
ENABLED =

Returns by default the gem is enabled.

Returns:

  • (true)

    by default the gem is enabled

true
DEBUG_LUA =

Returns by default we don’t debug the lua scripts because it is slow.

Returns:

  • (false)

    by default we don’t debug the lua scripts because it is slow

false
MAX_HISTORY =

Returns use a changelog history of 1_000 entries by default.

Returns:

  • (1_000)

    use a changelog history of 1_000 entries by default

1_000
REAPER =

Returns prefer the ruby reaper by default since the lua reaper still has problems.

Returns:

  • (:ruby)

    prefer the ruby reaper by default since the lua reaper still has problems

:ruby
REAPER_COUNT =

Returns reap 1_000 orphaned locks at a time by default.

Returns:

  • (1_000)

    reap 1_000 orphaned locks at a time by default

1_000
REAPER_INTERVAL =

Returns reap locks every 10 minutes.

Returns:

  • (600)

    reap locks every 10 minutes

600
REAPER_TIMEOUT =

Returns stop reaper after 10 seconds.

Returns:

  • (10)

    stop reaper after 10 seconds

10
REAPER_RESURRECTOR_INTERVAL =

Returns check if reaper is dead each 3600 seconds.

Returns:

  • (3600)

    check if reaper is dead each 3600 seconds

3600
REAPER_RESURRECTOR_ENABLED =

Returns enable reaper resurrector.

Returns:

  • (false)

    enable reaper resurrector

false
USE_LOCK_INFO =

Returns while useful it also adds overhead so disable lock_info by default.

Returns:

  • (false)

    while useful it also adds overhead so disable lock_info by default

false
RAISE_ON_CONFIG_ERROR =

Returns by default we don’t raise validation errors for workers.

Returns:

  • (false)

    by default we don’t raise validation errors for workers

false
REDIS_VERSION =

Returns default redis version is only to avoid NoMethodError on nil.

Returns:

  • (0.0.0)

    default redis version is only to avoid NoMethodError on nil

"0.0.0"
DIGEST_ALGORITHM =

Returns default digest algorithm :modern or :legacy.

Returns:

  • (:legacy)

    default digest algorithm :modern or :legacy

:legacy
LOCKSMITH_EXECUTOR =

Returns by default a bounded ThreadPoolExecutor is built lazily on first use.

Returns:

  • (nil)

    by default a bounded ThreadPoolExecutor is built lazily on first use

nil
ON_CONFLICT =

Returns by default no global on_conflict strategy (use per-job config).

Returns:

  • (nil)

    by default no global on_conflict strategy (use per-job config)

nil

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfig

Returns a new instance of Config.



36
37
38
39
40
# File 'lib/sidekiq_unique_jobs/config.rb', line 36

def initialize(*)
  super
  @redis_version_mutex = Mutex.new
  @default_executor_mutex = Mutex.new
end

Class Method Details

.defaultSidekiqUniqueJobs::Config

Returns a default configuration

Examples:

SidekiqUniqueJobs::Config.default => <concurrent/mutable_struct/thread_safe_config SidekiqUniqueJobs::Config {
default_lock_timeout: 0,
default_lock_ttl: nil,
enabled: true,
lock_prefix: "uniquejobs",
logger: #<Sidekiq::Logger:0x00007f81e096b0e0 @level=1 ...>,
locks: {
  around_perform: SidekiqUniqueJobs::Lock::WhileExecuting,
  while_busy: SidekiqUniqueJobs::Lock::WhileExecuting,
  while_executing: SidekiqUniqueJobs::Lock::WhileExecuting,
  while_working: SidekiqUniqueJobs::Lock::WhileExecuting,
  while_executing_reject: SidekiqUniqueJobs::Lock::WhileExecutingReject,
  until_executing: SidekiqUniqueJobs::Lock::UntilExecuting,
  while_enqueued: SidekiqUniqueJobs::Lock::UntilExecuting,
  until_expired: SidekiqUniqueJobs::Lock::UntilExpired,
  until_completed: SidekiqUniqueJobs::Lock::UntilExecuted,
  until_executed: SidekiqUniqueJobs::Lock::UntilExecuted,
  until_performed: SidekiqUniqueJobs::Lock::UntilExecuted,
  until_processed: SidekiqUniqueJobs::Lock::UntilExecuted,
  until_and_while_executing: SidekiqUniqueJobs::Lock::UntilAndWhileExecuting,
  until_successfully_completed: SidekiqUniqueJobs::Lock::UntilExecuted
},
strategies: {
  log: SidekiqUniqueJobs::OnConflict::Log,
  raise: SidekiqUniqueJobs::OnConflict::Raise,
  reject: SidekiqUniqueJobs::OnConflict::Reject,
  replace: SidekiqUniqueJobs::OnConflict::Replace,
  reschedule: SidekiqUniqueJobs::OnConflict::Reschedule
},
debug_lua: false,
max_history: 1000,
reaper:: ruby,
reaper_count: 1000,
lock_info: false,
raise_on_config_error: false,
}>

Returns:



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/sidekiq_unique_jobs/config.rb', line 196

def self.default
  new(
    LOCK_TIMEOUT,
    LOCK_TTL,
    ENABLED,
    PREFIX,
    Sidekiq.logger,
    LOGGER_ENABLED,
    LOCKS,
    STRATEGIES,
    DEBUG_LUA,
    MAX_HISTORY,
    REAPER,
    REAPER_COUNT,
    REAPER_INTERVAL,
    REAPER_TIMEOUT,
    REAPER_RESURRECTOR_INTERVAL,
    REAPER_RESURRECTOR_ENABLED,
    USE_LOCK_INFO,
    RAISE_ON_CONFIG_ERROR,
    REDIS_VERSION,
    DIGEST_ALGORITHM,
    LOCKSMITH_EXECUTOR,
    ON_CONFLICT,
  )
end

Instance Method Details

#add_lock(name, klass) ⇒ void

This method returns an undefined value.

Adds a lock type to the configuration. It will raise if the lock exists already

Examples:

Add a custom lock

add_lock(:my_lock, CustomLocks::MyLock)

Parameters:

  • name (String, Symbol)

    the name of the lock

  • klass (Class)

    the class describing the lock

Raises:

  • DuplicateLock when the name already exists



299
300
301
302
303
304
305
# File 'lib/sidekiq_unique_jobs/config.rb', line 299

def add_lock(name, klass)
  lock_sym = name.to_sym
  raise DuplicateLock, ":#{name} already defined, please use another name" if locks.key?(lock_sym)

  new_locks = locks.dup.merge(lock_sym => klass).freeze
  self.locks = new_locks
end

#add_strategy(name, klass) ⇒ Object

Adds an on_conflict strategy to the configuration.

Examples:

Add a custom strategy

add_lock(:my_strategy, CustomStrategies::MyStrategy)

Parameters:

  • name (String)

    the name of the custom strategy

  • klass (Class)

    the class describing the strategy

Raises:



318
319
320
321
322
323
324
# File 'lib/sidekiq_unique_jobs/config.rb', line 318

def add_strategy(name, klass)
  strategy_sym = name.to_sym
  raise DuplicateStrategy, ":#{name} already defined, please use another name" if strategies.key?(strategy_sym)

  new_strategies = strategies.dup.merge(strategy_sym => klass).freeze
  self.strategies = new_strategies
end

#class_nameString

Memoized variable to get the class name

Returns:

  • (String)

    name of the class



282
283
284
# File 'lib/sidekiq_unique_jobs/config.rb', line 282

def class_name
  @class_name ||= self.class.name
end

#default_lock_timeoutnil, Integer

Deprecated.

Default Lock Timeout

Returns:

  • (nil, Integer)

    configured value or nil



270
271
272
273
274
# File 'lib/sidekiq_unique_jobs/config.rb', line 270

def default_lock_timeout
  warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated. " \
       "Please use `#{class_name}#lock_timeout` instead."
  lock_timeout
end

#default_lock_timeout=(obj) ⇒ Integer

Deprecated.

Set new value for default_lock_timeout

Parameters:

  • obj (Integer)

    value to set (seconds)

Returns:

  • (Integer)


245
246
247
248
249
# File 'lib/sidekiq_unique_jobs/config.rb', line 245

def default_lock_timeout=(obj)
  warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated. " \
       "Please use `#{class_name}#lock_timeout=` instead."
  self.lock_timeout = obj
end

#default_lock_ttlnil, Integer

Deprecated.

Default lock TTL (Time To Live)

Returns:

  • (nil, Integer)

    configured value or nil



257
258
259
260
261
# File 'lib/sidekiq_unique_jobs/config.rb', line 257

def default_lock_ttl
  warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated. " \
       "Please use `#{class_name}#lock_ttl` instead."
  lock_ttl
end

#default_lock_ttl=(obj) ⇒ <type>

Deprecated.

Set the default_lock_ttl

Parameters:

  • obj (Integer)

    value to set (seconds)

Returns:

  • (<type>)

    <description>



231
232
233
234
235
# File 'lib/sidekiq_unique_jobs/config.rb', line 231

def default_lock_ttl=(obj)
  warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated. " \
       "Please use `#{class_name}#lock_ttl=` instead."
  self.lock_ttl = obj
end

#digest_algorithm=(value) ⇒ Symbol

Sets digest_algorithm to either :modern or :legacy

Parameters:

  • value (Symbol)

Returns:

  • (Symbol)

    the new value



333
334
335
336
337
338
339
# File 'lib/sidekiq_unique_jobs/config.rb', line 333

def digest_algorithm=(value)
  unless [:modern, :legacy].include?(value)
    raise ArgumentError, "Invalid digest algorithm: #{value} (should be :modern or :legacy)"
  end

  super
end

#locksmith_executorConcurrent::AbstractExecutorService

The executor for Locksmith promises

Returns the user-configured executor if set, otherwise lazily builds a bounded default to prevent unbounded thread growth.

Returns:

  • (Concurrent::AbstractExecutorService)


349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/sidekiq_unique_jobs/config.rb', line 349

def locksmith_executor
  user_configured = super # reads the raw struct slot without calling this override
  return user_configured if user_configured
  return @default_locksmith_executor if @default_locksmith_executor

  @default_executor_mutex.synchronize do
    @default_locksmith_executor ||= Concurrent::ThreadPoolExecutor.new(
      min_threads: 1,
      max_threads: 50,
      max_queue: 100,
      fallback_policy: :caller_runs,
    )
  end
end

#redis_versionString

The current version of redis

Thread-safe: Uses mutex to prevent multiple threads from fetching version simultaneously

Returns:

  • (String)

    a version string eg. ‘5.0.1`



389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/sidekiq_unique_jobs/config.rb', line 389

def redis_version
  # Fast path: if already fetched, return immediately without locking
  return current_redis_version if current_redis_version != REDIS_VERSION

  # Slow path: fetch version with mutex protection
  @redis_version_mutex.synchronize do
    # Double-check inside mutex in case another thread just fetched it
    self.current_redis_version = SidekiqUniqueJobs.fetch_redis_version if current_redis_version == REDIS_VERSION
  end

  current_redis_version
end

#shutdown_executorvoid

This method returns an undefined value.

Shuts down the default locksmith executor if one was created

Only shuts down the internally-created executor, not user-configured ones, since the user is responsible for managing their own executor lifecycle.



372
373
374
375
376
377
378
379
380
# File 'lib/sidekiq_unique_jobs/config.rb', line 372

def shutdown_executor
  @default_executor_mutex.synchronize do
    return unless @default_locksmith_executor

    @default_locksmith_executor.shutdown
    @default_locksmith_executor.wait_for_termination(5)
    @default_locksmith_executor = nil
  end
end