Class: Wurk::JobRetry
- Inherits:
-
Object
- Object
- Wurk::JobRetry
- Includes:
- Component
- Defined in:
- lib/wurk/job_retry.rb
Overview
Owns the retry pipeline. When perform raises, JobRetry decides whether to
reschedule (retry ZSET, exponential backoff + jitter), drop, kill, or
send to the morgue. Wire-compat sacred: error_message / error_class /
retry_count / failed_at / retried_at / error_backtrace field names and
encodings (base64 of zlib of JSON for the backtrace) match Sidekiq byte
for byte — third-party gems and the dashboard read them directly.
Two entry points wrap the dispatch onion in Processor#dispatch:
* `global(jobstr, queue)` — outermost, no job instance required.
Rescues `Exception` so pre-instantiation failures (const_get, reloader)
still get a retry recorded. Re-raises `Handled` so the processor
skips ACK logging.
* `local(jobinst, jobstr, queue)` — inner, runs after the worker is
instantiated. Honors per-class `sidekiq_retry_in_block` /
`sidekiq_retries_exhausted_block` (and the wrapped-class variants).
Raises `Handled` after booking the retry so `global` does not double-
process the failure.
Spec: docs/target/sidekiq-free.md §17.
Defined Under Namespace
Constant Summary collapse
- DEFAULT_MAX_RETRY_ATTEMPTS =
25
Instance Attribute Summary collapse
-
#config ⇒ Object
included
from Component
readonly
Returns the value of attribute config.
Instance Method Summary collapse
- #default_tag(dir = Dir.pwd) ⇒ Object included from Component
-
#fire_event(event, oneshot: true, reverse: false, reraise: false) ⇒ Object
included
from Component
Invokes lifecycle hooks for
event. -
#global(jobstr, queue) ⇒ Object
Outermost retry guard.
-
#handle_exception(ex, ctx = {}) ⇒ Object
Component's
handle_exceptiondelegates toconfig.handle_exception. - #hostname ⇒ Object included from Component
- #identity ⇒ Object included from Component
-
#initialize(capsule) ⇒ JobRetry
constructor
A new instance of JobRetry.
-
#leader? ⇒ Boolean
included
from Component
True iff this process currently holds the cluster
dear-leaderlock. -
#local(jobinst, jobstr, queue) ⇒ Object
Per-job retry guard.
-
#logger ⇒ Object
included
from Component
--- delegated to config -------------------------------------------.
- #mono_ms ⇒ Object included from Component
- #process_nonce ⇒ Object included from Component
-
#real_ms ⇒ Object
included
from Component
--- clocks ---------------------------------------------------------.
- #redis ⇒ Object included from Component
-
#safe_thread(name, priority: nil, &block) ⇒ Object
included
from Component
Spawns a named thread that runs
blockunderwatchdog(name). -
#tid ⇒ Object
included
from Component
--- identity -------------------------------------------------------.
-
#watchdog(last_words) ⇒ Object
included
from Component
Wraps a block at a thread boundary: any unhandled exception is reported via handle_exception (so it lands in error_handlers / the log) and then re-raised.
Constructor Details
#initialize(capsule) ⇒ JobRetry
Returns a new instance of JobRetry.
40 41 42 43 44 45 |
# File 'lib/wurk/job_retry.rb', line 40 def initialize(capsule) @capsule = capsule @config = capsule @max_retries = inner_config_get(:max_retries) || DEFAULT_MAX_RETRY_ATTEMPTS @backtrace_cleaner = inner_config_get(:backtrace_cleaner) end |
Instance Attribute Details
#config ⇒ Object (readonly) Originally defined in module Component
Returns the value of attribute config.
Instance Method Details
#default_tag(dir = Dir.pwd) ⇒ Object Originally defined in module Component
#fire_event(event, oneshot: true, reverse: false, reraise: false) ⇒ Object Originally defined in module Component
Invokes lifecycle hooks for event. Hooks run in registration order
(or LIFO when reverse: true, used for teardown). A raise in one hook
is reported via handle_exception and does NOT stop the next hook unless
reraise: true (used in tests / fail-fast boot). oneshot: true
clears the bucket after dispatch so the event can't fire twice.
#global(jobstr, queue) ⇒ Object
Outermost retry guard. Rescues Exception so const_get / reloader
failures still get a retry. Handled is re-raised intact; Shutdown
bubbles up so the swarm can drain.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/wurk/job_retry.rb', line 50 def global(jobstr, queue) yield rescue Handled, Wurk::Shutdown raise rescue Exception => e # rubocop:disable Lint/RescueException raise Wurk::Shutdown if exception_caused_by_shutdown?(e) msg = Wurk.load_json(jobstr) if msg['retry'] process_retry(nil, msg, queue, e) else run_death_handlers(msg, e) end raise Handled end |
#handle_exception(ex, ctx = {}) ⇒ Object
Component's handle_exception delegates to config.handle_exception.
When initialized with a Capsule, that's not defined directly; route
through the underlying Configuration.
90 91 92 |
# File 'lib/wurk/job_retry.rb', line 90 def handle_exception(ex, ctx = {}) inner_config.handle_exception(ex, ctx) end |
#hostname ⇒ Object Originally defined in module Component
#identity ⇒ Object Originally defined in module Component
#leader? ⇒ Boolean Originally defined in module Component
True iff this process currently holds the cluster dear-leader lock.
Per spec, the check is performed at call time (Wurk does not cache);
callers must not poll faster than the 60s follower cadence. Returns
false unconditionally when WURK_LEADER=false (or SIDEKIQ_LEADER=false)
is set on the process (opt-out hot-standby). Any Redis error is swallowed →
false, so a transient partition can't propagate as an exception into user
code.
Spec: docs/target/sidekiq-ent.md §6.1.
#local(jobinst, jobstr, queue) ⇒ Object
Per-job retry guard. Same rescue semantics as global but the worker
instance is in hand, so per-class sidekiq_retry_in_block and
sidekiq_retries_exhausted_block can run. Raises Handled to short-
circuit global's rescue.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/wurk/job_retry.rb', line 71 def local(jobinst, jobstr, queue) yield rescue Handled, Wurk::Shutdown raise rescue Exception => e # rubocop:disable Lint/RescueException raise Wurk::Shutdown if exception_caused_by_shutdown?(e) msg = Wurk.load_json(jobstr) msg['retry'] = jobinst.class.['retry'] if msg['retry'].nil? raise e unless msg['retry'] process_retry(jobinst, msg, queue, e) raise Handled end |
#logger ⇒ Object Originally defined in module Component
--- delegated to config -------------------------------------------
#mono_ms ⇒ Object Originally defined in module Component
#process_nonce ⇒ Object Originally defined in module Component
#real_ms ⇒ Object Originally defined in module Component
--- clocks ---------------------------------------------------------
#redis ⇒ Object Originally defined in module Component
#safe_thread(name, priority: nil, &block) ⇒ Object Originally defined in module Component
Spawns a named thread that runs block under watchdog(name). The
parent must retain the returned Thread; otherwise GC may not, but
report_on_exception is disabled so we don't double-log on death.
#tid ⇒ Object Originally defined in module Component
--- identity -------------------------------------------------------
#watchdog(last_words) ⇒ Object Originally defined in module Component
Wraps a block at a thread boundary: any unhandled exception is reported
via handle_exception (so it lands in error_handlers / the log) and then
re-raised. last_words is the component label included in the context.