Class: Wurk::CLI
Overview
Standalone CLI. Loads from ‘exe/wurk` — never loads `wurk/rails` so the binary works without the Rails engine (the host app might not be Rails). Singleton because there is exactly one process-wide CLI; tests construct fresh `.new` instances to keep state isolated.
Spec: docs/target/sidekiq-free.md §21 (Sidekiq::CLI).
Constant Summary collapse
- MIN_REDIS_VERSION =
Minimum Redis version Wurk supports — same as Sidekiq 8.x. The job JSON format and Lua scripts rely on commands introduced in Redis 7.
'7.0.0'- BACKTRACE_DUMPER =
Thread-backtrace dumper used by both TTIN and INFO. Same body — INFO is the modern name, TTIN is kept for parity with older Sidekiq users.
lambda do |cli| Thread.list.each do |thread| cli.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}" if thread.backtrace cli.logger.warn thread.backtrace.join("\n") else cli.logger.warn '<no backtrace available>' end end end
- SIGNAL_HANDLERS =
{ 'INT' => ->(_cli) { raise Interrupt }, 'TERM' => ->(_cli) { raise Interrupt }, 'TSTP' => lambda do |cli| cli.logger.info 'Received TSTP, no longer accepting new work' cli.launcher.quiet end, 'TTIN' => BACKTRACE_DUMPER, 'INFO' => BACKTRACE_DUMPER }.freeze
- OPTION_FLAGS =
Table-driven so adding a flag doesn’t grow ‘define_value_flags`’s ABC size and the surface matches the Sidekiq docs row-for-row. The 5th column is the assignment transform: ‘:to_i` parses as Integer, `:append` pushes onto a list (only `-q` uses that), nil = assign as-is.
[ ['-c', '--concurrency INT', :concurrency, 'processor threads to use', :to_i], ['-e', '--environment ENV', :environment, 'Application environment'], ['-g', '--tag TAG', :tag, 'Process tag for procline'], ['-q', '--queue QUEUE[,WEIGHT]', :queues, 'Queues to process with optional weights', :append], ['-r', '--require [PATH|DIR]', :require, 'Location of Rails app or .rb file to require'], ['-t', '--timeout NUM', :timeout, 'Shutdown timeout', :to_i], ['-v', '--verbose', :verbose, 'Print more verbose output'], ['-C', '--config PATH', :config_file, 'path to YAML config file'] ].freeze
Constants included from Component
Wurk::Component::DEFAULT_THREAD_PRIORITY, Wurk::Component::PROCESS_NONCE
Instance Attribute Summary collapse
-
#config ⇒ Object
Returns the value of attribute config.
-
#environment ⇒ Object
Returns the value of attribute environment.
-
#launcher ⇒ Object
Returns the value of attribute launcher.
Class Method Summary collapse
- .instance ⇒ Object
-
.reset_instance! ⇒ Object
Test seam: parallel suites can’t share the singleton.
Instance Method Summary collapse
- #handle_signal(sig) ⇒ Object
-
#initialize ⇒ CLI
constructor
A new instance of CLI.
-
#parse(args = ARGV.dup) ⇒ Object
‘parse` is split from `run` so tests can drive option parsing without touching Redis or booting the host app.
-
#run(boot_app: true, warmup: true) ⇒ Object
‘boot_app:` / `warmup:` are test seams.
Methods included from Component
#default_tag, #fire_event, #handle_exception, #hostname, #identity, #leader?, #logger, #mono_ms, #process_nonce, #real_ms, #redis, #safe_thread, #tid, #watchdog
Constructor Details
#initialize ⇒ CLI
Returns a new instance of CLI.
77 78 79 80 81 82 |
# File 'lib/wurk/cli.rb', line 77 def initialize @config = nil @launcher = nil @environment = nil @parser = nil end |
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
66 67 68 |
# File 'lib/wurk/cli.rb', line 66 def config @config end |
#environment ⇒ Object
Returns the value of attribute environment.
66 67 68 |
# File 'lib/wurk/cli.rb', line 66 def environment @environment end |
#launcher ⇒ Object
Returns the value of attribute launcher.
66 67 68 |
# File 'lib/wurk/cli.rb', line 66 def launcher @launcher end |
Class Method Details
.instance ⇒ Object
68 69 70 |
# File 'lib/wurk/cli.rb', line 68 def self.instance @instance ||= new end |
.reset_instance! ⇒ Object
Test seam: parallel suites can’t share the singleton.
73 74 75 |
# File 'lib/wurk/cli.rb', line 73 def self.reset_instance! @instance = nil end |
Instance Method Details
#handle_signal(sig) ⇒ Object
110 111 112 113 114 115 116 |
# File 'lib/wurk/cli.rb', line 110 def handle_signal(sig) logger.debug { "Got #{sig} signal" } handler = SIGNAL_HANDLERS[sig] return logger.warn("No #{sig} signal handler registered, ignoring") unless handler handler.call(self) end |
#parse(args = ARGV.dup) ⇒ Object
‘parse` is split from `run` so tests can drive option parsing without touching Redis or booting the host app.
86 87 88 89 90 91 92 |
# File 'lib/wurk/cli.rb', line 86 def parse(args = ARGV.dup) @config ||= Wurk.default_configuration (args) initialize_logger validate! self end |
#run(boot_app: true, warmup: true) ⇒ Object
‘boot_app:` / `warmup:` are test seams. Production always passes true.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/wurk/cli.rb', line 95 def run(boot_app: true, warmup: true) boot_application if boot_app self_read, self_write = ::IO.pipe trap_signals(self_write) validate_redis! validate_pool_sizes! @config[:identity] = identity # Force lazy server-middleware chain so worker threads don't race # against each other constructing it. Spec: Sidekiq::CLI line 104. @config.server_middleware ::Process.warmup if warmup && ::Process.respond_to?(:warmup) && ENV['RUBY_DISABLE_WARMUP'] != '1' fire_event(:startup, reverse: false, reraise: true) launch(self_read) end |