wurk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +43 -0
- data/CONTRIBUTING.md +73 -0
- data/LICENSE +21 -0
- data/README.md +137 -0
- data/SECURITY.md +39 -0
- data/app/controllers/wurk/api/pagination.rb +67 -0
- data/app/controllers/wurk/api/serializers.rb +131 -0
- data/app/controllers/wurk/api_controller.rb +248 -0
- data/app/controllers/wurk/application_controller.rb +7 -0
- data/app/controllers/wurk/dashboard_controller.rb +48 -0
- data/config/locales/en.yml +15 -0
- data/config/routes.rb +34 -0
- data/exe/wurk +22 -0
- data/lib/active_job/queue_adapters/wurk_adapter.rb +96 -0
- data/lib/generators/wurk/install/install_generator.rb +22 -0
- data/lib/generators/wurk/install/templates/wurk.rb +16 -0
- data/lib/wurk/active_job/wrapper.rb +32 -0
- data/lib/wurk/api/fast.rb +78 -0
- data/lib/wurk/batch/buffer.rb +26 -0
- data/lib/wurk/batch/callback_job.rb +37 -0
- data/lib/wurk/batch/callbacks.rb +176 -0
- data/lib/wurk/batch/client_middleware.rb +27 -0
- data/lib/wurk/batch/death_handler.rb +39 -0
- data/lib/wurk/batch/empty.rb +21 -0
- data/lib/wurk/batch/server_middleware.rb +62 -0
- data/lib/wurk/batch/status.rb +140 -0
- data/lib/wurk/batch.rb +351 -0
- data/lib/wurk/batch_set.rb +67 -0
- data/lib/wurk/capsule.rb +176 -0
- data/lib/wurk/cli.rb +349 -0
- data/lib/wurk/client/buffered.rb +372 -0
- data/lib/wurk/client.rb +330 -0
- data/lib/wurk/compat.rb +136 -0
- data/lib/wurk/component.rb +136 -0
- data/lib/wurk/configuration.rb +373 -0
- data/lib/wurk/context.rb +35 -0
- data/lib/wurk/cron.rb +636 -0
- data/lib/wurk/dashboard_manifest.rb +39 -0
- data/lib/wurk/dead_set.rb +78 -0
- data/lib/wurk/deploy.rb +91 -0
- data/lib/wurk/embedded.rb +94 -0
- data/lib/wurk/encryption.rb +276 -0
- data/lib/wurk/engine.rb +81 -0
- data/lib/wurk/fetcher/reaper.rb +264 -0
- data/lib/wurk/fetcher/reliable.rb +138 -0
- data/lib/wurk/fetcher.rb +11 -0
- data/lib/wurk/health.rb +193 -0
- data/lib/wurk/heartbeat.rb +211 -0
- data/lib/wurk/iterable_job.rb +292 -0
- data/lib/wurk/job/options.rb +70 -0
- data/lib/wurk/job.rb +33 -0
- data/lib/wurk/job_logger.rb +68 -0
- data/lib/wurk/job_record.rb +156 -0
- data/lib/wurk/job_retry.rb +320 -0
- data/lib/wurk/job_set.rb +212 -0
- data/lib/wurk/job_util.rb +162 -0
- data/lib/wurk/keys.rb +52 -0
- data/lib/wurk/launcher.rb +289 -0
- data/lib/wurk/leader.rb +221 -0
- data/lib/wurk/limiter/base.rb +138 -0
- data/lib/wurk/limiter/bucket.rb +80 -0
- data/lib/wurk/limiter/concurrent.rb +132 -0
- data/lib/wurk/limiter/leaky.rb +91 -0
- data/lib/wurk/limiter/points.rb +89 -0
- data/lib/wurk/limiter/server_middleware.rb +77 -0
- data/lib/wurk/limiter/unlimited.rb +48 -0
- data/lib/wurk/limiter/window.rb +80 -0
- data/lib/wurk/limiter.rb +255 -0
- data/lib/wurk/logger.rb +81 -0
- data/lib/wurk/lua/loader.rb +53 -0
- data/lib/wurk/lua.rb +187 -0
- data/lib/wurk/manager.rb +132 -0
- data/lib/wurk/metrics/history.rb +151 -0
- data/lib/wurk/metrics/query.rb +173 -0
- data/lib/wurk/metrics/rollup.rb +169 -0
- data/lib/wurk/metrics/statsd.rb +197 -0
- data/lib/wurk/metrics.rb +7 -0
- data/lib/wurk/middleware/chain.rb +128 -0
- data/lib/wurk/middleware/current_attributes.rb +87 -0
- data/lib/wurk/middleware/expiry.rb +50 -0
- data/lib/wurk/middleware/i18n.rb +63 -0
- data/lib/wurk/middleware/interrupt_handler.rb +45 -0
- data/lib/wurk/middleware/poison_pill.rb +149 -0
- data/lib/wurk/middleware.rb +34 -0
- data/lib/wurk/process_set.rb +243 -0
- data/lib/wurk/processor.rb +247 -0
- data/lib/wurk/queue.rb +108 -0
- data/lib/wurk/queues.rb +80 -0
- data/lib/wurk/rails.rb +9 -0
- data/lib/wurk/railtie.rb +28 -0
- data/lib/wurk/redis_pool.rb +79 -0
- data/lib/wurk/retry_set.rb +17 -0
- data/lib/wurk/scheduled.rb +189 -0
- data/lib/wurk/scheduled_set.rb +18 -0
- data/lib/wurk/sorted_entry.rb +95 -0
- data/lib/wurk/stats.rb +190 -0
- data/lib/wurk/swarm/child_boot.rb +105 -0
- data/lib/wurk/swarm.rb +260 -0
- data/lib/wurk/testing.rb +102 -0
- data/lib/wurk/topology.rb +74 -0
- data/lib/wurk/unique.rb +240 -0
- data/lib/wurk/version.rb +5 -0
- data/lib/wurk/web/config.rb +180 -0
- data/lib/wurk/web/enterprise.rb +138 -0
- data/lib/wurk/web/search.rb +139 -0
- data/lib/wurk/web.rb +25 -0
- data/lib/wurk/work_set.rb +116 -0
- data/lib/wurk/worker/setter.rb +93 -0
- data/lib/wurk/worker.rb +216 -0
- data/lib/wurk.rb +238 -0
- data/vendor/assets/dashboard/assets/index-8P3N_m1X.js +152 -0
- data/vendor/assets/dashboard/assets/index-Bqz4_SOQ.css +1 -0
- data/vendor/assets/dashboard/index.html +13 -0
- data/vendor/assets/dashboard/wurk-manifest.json +4 -0
- metadata +232 -0
data/lib/wurk/worker.rb
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'worker/setter'
|
|
4
|
+
|
|
5
|
+
module Wurk
|
|
6
|
+
# The user-facing DSL: `include Wurk::Worker` (aliased to Sidekiq::Worker).
|
|
7
|
+
# Owns `sidekiq_options`, `perform_async`, `perform_in`, `perform_at`,
|
|
8
|
+
# `set`, `sidekiq_retry_in`, etc.
|
|
9
|
+
#
|
|
10
|
+
# Spec: docs/target/sidekiq-free.md §6 (Sidekiq::Job).
|
|
11
|
+
module Worker
|
|
12
|
+
# Interval values below this threshold are interpreted as seconds-from-now;
|
|
13
|
+
# values at or above are treated as absolute epoch timestamps.
|
|
14
|
+
# Threshold matches Sidekiq exactly — wire-compat sacred.
|
|
15
|
+
SCHEDULED_THRESHOLD = 1_000_000_000
|
|
16
|
+
|
|
17
|
+
def self.included(base)
|
|
18
|
+
base.extend(ClassMethods)
|
|
19
|
+
base.module_eval { attr_accessor :jid, :_context }
|
|
20
|
+
base.singleton_class.module_eval do
|
|
21
|
+
attr_accessor :sidekiq_retry_in_block, :sidekiq_retries_exhausted_block
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Module-level test helpers: `Sidekiq::Worker.jobs / clear_all / drain_all`
|
|
26
|
+
# operate across every job class (spec §24.3). Resolved lazily so the
|
|
27
|
+
# testing constants need not be loaded when Worker is.
|
|
28
|
+
def self.jobs = ::Wurk::Queues.jobs
|
|
29
|
+
def self.clear_all = ::Wurk::Queues.clear_all
|
|
30
|
+
def self.drain_all = ::Wurk::Testing.drain_all
|
|
31
|
+
|
|
32
|
+
def logger
|
|
33
|
+
Wurk.logger
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Cooperative cancellation flag for IterableJob and long-running jobs.
|
|
37
|
+
# Returns false when no processor context has been attached.
|
|
38
|
+
def interrupted?
|
|
39
|
+
ctx = @_context
|
|
40
|
+
ctx.respond_to?(:stopping?) && ctx.stopping?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Batch helpers (Pro). Available on every worker — return nil when the
|
|
44
|
+
# current job did not originate from a batch.
|
|
45
|
+
#
|
|
46
|
+
# Spec: docs/target/sidekiq-pro.md §2.6.
|
|
47
|
+
def bid
|
|
48
|
+
@bid
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @api private — Processor sets this from job_hash['bid'] before perform.
|
|
52
|
+
attr_writer :bid
|
|
53
|
+
|
|
54
|
+
def batch
|
|
55
|
+
return nil if @bid.nil?
|
|
56
|
+
|
|
57
|
+
Wurk::Batch.new(@bid)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# False if the batch was invalidated. Workers should `return unless
|
|
61
|
+
# valid_within_batch?` to short-circuit work for cancelled batches.
|
|
62
|
+
def valid_within_batch?
|
|
63
|
+
return true if @bid.nil?
|
|
64
|
+
|
|
65
|
+
batch.valid?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
module ClassMethods # rubocop:disable Metrics/ModuleLength
|
|
69
|
+
def sidekiq_options(opts = {})
|
|
70
|
+
merged = get_sidekiq_options.merge(opts.transform_keys(&:to_s))
|
|
71
|
+
@sidekiq_options_hash = merged
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Sidekiq's public API name — wire-compat sacred. Must stay `get_sidekiq_options`.
|
|
75
|
+
def get_sidekiq_options # rubocop:disable Naming/AccessorMethodName
|
|
76
|
+
@sidekiq_options_hash ||= inherited_sidekiq_options # rubocop:disable Naming/MemoizedInstanceVariableName
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def sidekiq_options_hash
|
|
80
|
+
get_sidekiq_options
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def queue_as(queue)
|
|
84
|
+
sidekiq_options('queue' => queue.to_s)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def sidekiq_retry_in(&block)
|
|
88
|
+
self.sidekiq_retry_in_block = block
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def sidekiq_retries_exhausted(&block)
|
|
92
|
+
self.sidekiq_retries_exhausted_block = block
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def perform_async(*)
|
|
96
|
+
Wurk::Worker::Setter.new(self, {}).perform_async(*)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def perform_inline(*)
|
|
100
|
+
new.perform(*)
|
|
101
|
+
end
|
|
102
|
+
alias perform_sync perform_inline
|
|
103
|
+
|
|
104
|
+
def perform_in(interval, *)
|
|
105
|
+
Wurk::Worker::Setter.new(self, {}).perform_in(interval, *)
|
|
106
|
+
end
|
|
107
|
+
alias perform_at perform_in
|
|
108
|
+
|
|
109
|
+
def perform_bulk(items, **)
|
|
110
|
+
Wurk::Worker::Setter.new(self, {}).perform_bulk(items, **)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def set(opts)
|
|
114
|
+
Wurk::Worker::Setter.new(self, opts)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def client_push(item)
|
|
118
|
+
raise ArgumentError, "Job arguments to #{name || self} must have string keys" if symbol_keyed?(item)
|
|
119
|
+
|
|
120
|
+
build_client.push(item)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def build_client
|
|
124
|
+
pool = get_sidekiq_options['pool']
|
|
125
|
+
Wurk::Client.new(pool: pool)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# --- Sidekiq::Testing class-level helpers (spec §24.3) --------------
|
|
129
|
+
# Only meaningful in :fake / :inline mode; the in-memory store is empty
|
|
130
|
+
# otherwise.
|
|
131
|
+
|
|
132
|
+
def queue
|
|
133
|
+
get_sidekiq_options['queue']
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Fake jobs enqueued for this class, across every queue.
|
|
137
|
+
def jobs
|
|
138
|
+
::Wurk::Queues.jobs_by_class[to_s] || []
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def clear
|
|
142
|
+
::Wurk::Queues.clear_class(to_s)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Run & remove every fake job for this class — including ones it enqueues
|
|
146
|
+
# mid-drain. Returns the count processed.
|
|
147
|
+
def drain
|
|
148
|
+
count = 0
|
|
149
|
+
while (job = ::Wurk::Queues.shift_class(to_s))
|
|
150
|
+
process_job(job)
|
|
151
|
+
count += 1
|
|
152
|
+
end
|
|
153
|
+
count
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Run & remove the first fake job for this class; EmptyQueueError if none.
|
|
157
|
+
def perform_one
|
|
158
|
+
job = ::Wurk::Queues.shift_class(to_s)
|
|
159
|
+
raise ::Wurk::Testing::EmptyQueueError, "no #{self} jobs were found" if job.nil?
|
|
160
|
+
|
|
161
|
+
process_job(job)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Execute a normalized job hash through the inline server-middleware chain
|
|
165
|
+
# (empty by default — see Wurk::Testing.server_middleware).
|
|
166
|
+
# Returns the value of the server-middleware `invoke` (i.e. the worker's
|
|
167
|
+
# `perform` return), matching Sidekiq::Testing — so `perform_one` yields
|
|
168
|
+
# the job result.
|
|
169
|
+
def process_job(job_hash)
|
|
170
|
+
instance = new
|
|
171
|
+
instance.jid = job_hash['jid']
|
|
172
|
+
instance.bid = job_hash['bid'] if instance.respond_to?(:bid=)
|
|
173
|
+
::Wurk::Testing.server_middleware.invoke(instance, job_hash, job_hash['queue'] || queue) do
|
|
174
|
+
execute_job(instance, job_hash['args'])
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def execute_job(worker, args)
|
|
179
|
+
worker.perform(*args)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def delay(*)
|
|
183
|
+
raise ArgumentError, "#{name || self}.delay is removed in Sidekiq 7+. Use #{name || 'klass'}.perform_async."
|
|
184
|
+
end
|
|
185
|
+
alias delay_for delay
|
|
186
|
+
alias delay_until delay
|
|
187
|
+
|
|
188
|
+
def inherited(subclass)
|
|
189
|
+
super
|
|
190
|
+
subclass.instance_variable_set(:@sidekiq_options_hash, get_sidekiq_options.dup)
|
|
191
|
+
inherit_block(subclass, :@sidekiq_retry_in_block)
|
|
192
|
+
inherit_block(subclass, :@sidekiq_retries_exhausted_block)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
private
|
|
196
|
+
|
|
197
|
+
def inherited_sidekiq_options
|
|
198
|
+
if superclass.respond_to?(:get_sidekiq_options)
|
|
199
|
+
superclass.get_sidekiq_options.dup
|
|
200
|
+
else
|
|
201
|
+
Wurk.default_job_options.dup
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def inherit_block(subclass, ivar)
|
|
206
|
+
return unless instance_variable_defined?(ivar)
|
|
207
|
+
|
|
208
|
+
subclass.instance_variable_set(ivar, instance_variable_get(ivar))
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def symbol_keyed?(item)
|
|
212
|
+
item.respond_to?(:keys) && item.keys.any?(Symbol)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
data/lib/wurk.rb
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Standalone entry point. Loading "wurk" must work without Rails.
|
|
4
|
+
# The engine and railtie live under "wurk/rails" and are only loaded
|
|
5
|
+
# when the host app opts in.
|
|
6
|
+
|
|
7
|
+
require_relative 'wurk/version'
|
|
8
|
+
require_relative 'wurk/keys'
|
|
9
|
+
require_relative 'wurk/redis_pool'
|
|
10
|
+
require_relative 'wurk/middleware'
|
|
11
|
+
require_relative 'wurk/middleware/chain'
|
|
12
|
+
require_relative 'wurk/component'
|
|
13
|
+
require_relative 'wurk/context'
|
|
14
|
+
require_relative 'wurk/logger'
|
|
15
|
+
require_relative 'wurk/job_logger'
|
|
16
|
+
require_relative 'wurk/capsule'
|
|
17
|
+
require_relative 'wurk/configuration'
|
|
18
|
+
require_relative 'wurk/job_util'
|
|
19
|
+
require_relative 'wurk/client'
|
|
20
|
+
require_relative 'wurk/client/buffered'
|
|
21
|
+
require_relative 'wurk/worker'
|
|
22
|
+
require_relative 'wurk/worker/setter'
|
|
23
|
+
require_relative 'wurk/job'
|
|
24
|
+
require_relative 'wurk/job/options'
|
|
25
|
+
require_relative 'wurk/queues'
|
|
26
|
+
require_relative 'wurk/testing'
|
|
27
|
+
require_relative 'wurk/iterable_job'
|
|
28
|
+
require_relative 'wurk/job_retry'
|
|
29
|
+
require_relative 'wurk/job_record'
|
|
30
|
+
require_relative 'wurk/queue'
|
|
31
|
+
require_relative 'wurk/sorted_entry'
|
|
32
|
+
require_relative 'wurk/job_set'
|
|
33
|
+
require_relative 'wurk/retry_set'
|
|
34
|
+
require_relative 'wurk/scheduled_set'
|
|
35
|
+
require_relative 'wurk/dead_set'
|
|
36
|
+
require_relative 'wurk/stats'
|
|
37
|
+
require_relative 'wurk/process_set'
|
|
38
|
+
require_relative 'wurk/work_set'
|
|
39
|
+
require_relative 'wurk/heartbeat'
|
|
40
|
+
require_relative 'wurk/fetcher'
|
|
41
|
+
require_relative 'wurk/fetcher/reliable'
|
|
42
|
+
require_relative 'wurk/processor'
|
|
43
|
+
require_relative 'wurk/manager'
|
|
44
|
+
require_relative 'wurk/lua'
|
|
45
|
+
require_relative 'wurk/scheduled'
|
|
46
|
+
require_relative 'wurk/launcher'
|
|
47
|
+
require_relative 'wurk/cli'
|
|
48
|
+
require_relative 'wurk/embedded'
|
|
49
|
+
require_relative 'wurk/swarm'
|
|
50
|
+
require_relative 'wurk/topology'
|
|
51
|
+
require_relative 'wurk/batch'
|
|
52
|
+
require_relative 'wurk/batch/status'
|
|
53
|
+
require_relative 'wurk/batch_set'
|
|
54
|
+
require_relative 'wurk/limiter'
|
|
55
|
+
require_relative 'wurk/cron'
|
|
56
|
+
require_relative 'wurk/leader'
|
|
57
|
+
require_relative 'wurk/unique'
|
|
58
|
+
require_relative 'wurk/encryption'
|
|
59
|
+
require_relative 'wurk/metrics'
|
|
60
|
+
require_relative 'wurk/metrics/statsd'
|
|
61
|
+
require_relative 'wurk/metrics/history'
|
|
62
|
+
require_relative 'wurk/metrics/query'
|
|
63
|
+
require_relative 'wurk/web'
|
|
64
|
+
require_relative 'wurk/deploy'
|
|
65
|
+
|
|
66
|
+
require 'json'
|
|
67
|
+
|
|
68
|
+
module Wurk
|
|
69
|
+
class Error < StandardError; end
|
|
70
|
+
|
|
71
|
+
# Raised inside a worker process to abort the run loop. User code must not
|
|
72
|
+
# rescue this — the swarm uses it to signal teardown across thread boundaries.
|
|
73
|
+
# Spec: docs/target/sidekiq-free.md §3.
|
|
74
|
+
class Shutdown < Interrupt; end
|
|
75
|
+
|
|
76
|
+
# Process-wide job option defaults. Per-class options from `sidekiq_options`
|
|
77
|
+
# take precedence; this hash is the floor.
|
|
78
|
+
DEFAULT_JOB_OPTIONS = { 'retry' => true, 'queue' => 'default' }.freeze
|
|
79
|
+
|
|
80
|
+
class << self
|
|
81
|
+
def configure_server(&)
|
|
82
|
+
configuration.configure_server(&)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def configure_client(&)
|
|
86
|
+
configuration.configure_client(&)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Embedded mode: caller runs Wurk inside its own process (Puma, rake task,
|
|
90
|
+
# etc.) without forking. Concurrency is defaulted to 2 — the GIL makes
|
|
91
|
+
# higher thread counts counterproductive inside a host process that has
|
|
92
|
+
# its own pool. The block can override anything before the Embedded
|
|
93
|
+
# instance is built. Returns a Wurk::Embedded the caller drives with
|
|
94
|
+
# `#run` / `#quiet` / `#stop`.
|
|
95
|
+
def configure_embed
|
|
96
|
+
if configuration.frozen?
|
|
97
|
+
raise FrozenError, 'Wurk configuration is frozen; build all embedded instances before calling run'
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
configuration.concurrency = 2
|
|
101
|
+
yield configuration if block_given?
|
|
102
|
+
Embedded.new(configuration)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def configuration
|
|
106
|
+
@configuration ||= Configuration.new
|
|
107
|
+
end
|
|
108
|
+
alias default_configuration configuration
|
|
109
|
+
|
|
110
|
+
def redis(&)
|
|
111
|
+
redis_pool.with(&)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Capsule-aware pool lookup. Thread-local override wins so per-capsule
|
|
115
|
+
# workers (`Thread.current[:wurk_capsule] = cap`) read from their own
|
|
116
|
+
# connections without leaking to the default capsule.
|
|
117
|
+
def redis_pool
|
|
118
|
+
(Thread.current[:wurk_capsule] || configuration.default_capsule).redis_pool
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def logger
|
|
122
|
+
configuration.logger
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# --- JSON ---------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
def load_json(string)
|
|
128
|
+
::JSON.parse(string)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def dump_json(object)
|
|
132
|
+
::JSON.generate(object)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# --- default job options -----------------------------------------
|
|
136
|
+
|
|
137
|
+
def default_job_options
|
|
138
|
+
@default_job_options ||= DEFAULT_JOB_OPTIONS.dup
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Merges (does not replace) into the current defaults. Keys are
|
|
142
|
+
# stringified so symbol-keyed callers don't shadow string keys.
|
|
143
|
+
def default_job_options=(hash)
|
|
144
|
+
@default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# --- strict args -------------------------------------------------
|
|
148
|
+
|
|
149
|
+
# Sets the global mode used by Wurk::JobUtil#verify_json.
|
|
150
|
+
# mode ∈ [:raise, :warn, false].
|
|
151
|
+
def strict_args!(mode = :raise)
|
|
152
|
+
@strict_args_mode = mode
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# `defined?` distinguishes "never set" from "set to false".
|
|
156
|
+
def strict_args_mode
|
|
157
|
+
defined?(@strict_args_mode) ? @strict_args_mode : Configuration::DEFAULTS[:on_complex_arguments]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# --- mode flags --------------------------------------------------
|
|
161
|
+
|
|
162
|
+
# Sidekiq-compatible test-mode entry point. Delegates to Wurk::Testing
|
|
163
|
+
# (the single source of truth for the mode): a block scopes the mode to the
|
|
164
|
+
# current thread; no block sets it globally. `Sidekiq.testing!` aliases here.
|
|
165
|
+
def testing!(mode = :fake, &) = Wurk::Testing.__set_test_mode(mode, &)
|
|
166
|
+
|
|
167
|
+
# True when in :fake or :inline mode (i.e. not pushing to real Redis).
|
|
168
|
+
def testing? = Wurk::Testing.enabled?
|
|
169
|
+
|
|
170
|
+
# True inside the swarm/manager process (set by exe/wurk / the railtie).
|
|
171
|
+
def server?
|
|
172
|
+
!!@server
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
attr_writer :server
|
|
176
|
+
|
|
177
|
+
# Wurk ships Pro+Ent features in the free gem; these flags exist solely
|
|
178
|
+
# for third-party gems that branch on Sidekiq.pro? / Sidekiq.ent?.
|
|
179
|
+
def pro?
|
|
180
|
+
false
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def ent?
|
|
184
|
+
false
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Batch worker classes (Empty, CallbackJob) and middleware load AFTER the
|
|
190
|
+
# Wurk module class << self block — they instantiate workers at load time
|
|
191
|
+
# via `sidekiq_options`, which reads Wurk.default_job_options.
|
|
192
|
+
require_relative 'wurk/batch/empty'
|
|
193
|
+
require_relative 'wurk/batch/callback_job'
|
|
194
|
+
require_relative 'wurk/batch/callbacks'
|
|
195
|
+
require_relative 'wurk/batch/client_middleware'
|
|
196
|
+
require_relative 'wurk/batch/server_middleware'
|
|
197
|
+
require_relative 'wurk/batch/death_handler'
|
|
198
|
+
|
|
199
|
+
# Expiry must register AFTER Batch::ServerMiddleware so it sits inside that
|
|
200
|
+
# middleware's onion — a skipped (expired) job then unwinds back through
|
|
201
|
+
# batch's `yield` and gets counted as a batch success on the way out.
|
|
202
|
+
# Spec: docs/target/sidekiq-pro.md §7.
|
|
203
|
+
require_relative 'wurk/middleware/expiry'
|
|
204
|
+
|
|
205
|
+
# Health probe HTTP server — opt-in via `config.health_check(port:)`. Loaded
|
|
206
|
+
# at top level so the constants resolve in Launcher#build_health_server even
|
|
207
|
+
# in standalone (no-Rails) boot.
|
|
208
|
+
require_relative 'wurk/health'
|
|
209
|
+
|
|
210
|
+
# Poison-pill detection — orphan recovery counter + dead set on threshold.
|
|
211
|
+
# Spec: docs/target/sidekiq-pro.md §3.2.
|
|
212
|
+
require_relative 'wurk/middleware/poison_pill'
|
|
213
|
+
|
|
214
|
+
# Limiter server middleware: catches OverLimit, reschedules onto the same
|
|
215
|
+
# queue with `Time.now + backoff` until `overrated` hits the reschedule cap.
|
|
216
|
+
# Registered AFTER Batch::ServerMiddleware so a rescheduled OverLimit
|
|
217
|
+
# unwinds back through the batch onion without ack'ing success.
|
|
218
|
+
# Spec: docs/target/sidekiq-ent.md §1.4.
|
|
219
|
+
Wurk.configuration.server_middleware.add(Wurk::Limiter::ServerMiddleware)
|
|
220
|
+
|
|
221
|
+
# Statsd metrics middleware: per-job count / success / failure / perform_dist
|
|
222
|
+
# emissions. No-op when `config.dogstatsd` is unset (Statsd.client returns
|
|
223
|
+
# nil and the middleware yields straight through), so auto-registering here
|
|
224
|
+
# has zero overhead for users who don't wire up a client. Matches Sidekiq
|
|
225
|
+
# Pro's behavior of installing the middleware as soon as the gem is loaded.
|
|
226
|
+
# Spec: docs/target/sidekiq-pro.md §9.
|
|
227
|
+
Wurk.configuration.server_middleware.add(Wurk::Metrics::Statsd)
|
|
228
|
+
|
|
229
|
+
# Pro Fast API: Lua-backed Queue#delete_job / #delete_by_class plus
|
|
230
|
+
# SortedSet#scan { |JobRecord| … }. Mixed in via include/prepend on the
|
|
231
|
+
# existing data API classes so the surface is wire-compat with Sidekiq Pro.
|
|
232
|
+
# Spec: docs/target/sidekiq-pro.md §11.
|
|
233
|
+
require_relative 'wurk/api/fast'
|
|
234
|
+
|
|
235
|
+
# Sidekiq aliases load last — every Wurk::* constant they reference must be
|
|
236
|
+
# fully defined first. compat.rb only redefines names, it does not gate
|
|
237
|
+
# behavior, so trailing the load order is safe.
|
|
238
|
+
require_relative 'wurk/compat'
|