Class: Wurk::SortedEntry
- Defined in:
- lib/wurk/sorted_entry.rb
Overview
One entry inside a sorted-set view (Retry/Scheduled/Dead). Carries the
member's score alongside the JobRecord so callers can re-target the
exact (score, value) pair when mutating Redis — sorted-set membership is
by value, but ZREM-by-value is faster than ZRANGEBYSCORE+filter.
The id field ("
Spec: docs/target/sidekiq-free.md §19.4.
Instance Attribute Summary collapse
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#score ⇒ Object
readonly
Returns the value of attribute score.
Instance Method Summary collapse
-
#add_to_queue ⇒ Object
Removes this entry and re-enqueues it via the client with the payload untouched.
- #at ⇒ Object
-
#delete ⇒ Object
Removes this entry from the parent set.
- #error? ⇒ Boolean
- #id ⇒ Object
-
#initialize(parent, score, item) ⇒ SortedEntry
constructor
A new instance of SortedEntry.
-
#kill ⇒ Object
Removes this entry from its parent set and writes it to the dead set.
-
#queue ⇒ Object
JobRecord resolves the queue eagerly and only from a pre-parsed Hash; a sorted-set entry is almost always built from the raw JSON string, so read it off the payload instead.
-
#reschedule(at) ⇒ Object
Shifts the score by the delta to
at, returning the new score like Sidekiq's ZINCRBY does. -
#restore_after_failed_push ⇒ Object
Puts the original bytes back at the original score, after this entry was removed and its push failed.
-
#retry ⇒ Object
Same flow but decrements
retry_countfirst: the count was already incremented when the job entered the retry set, and the next failure bumps it again — without the decrement a manual "Retry now" would consume an attempt.
Constructor Details
#initialize(parent, score, item) ⇒ SortedEntry
Returns a new instance of SortedEntry.
21 22 23 24 25 26 27 28 29 30 |
# File 'lib/wurk/sorted_entry.rb', line 21 def initialize(parent, score, item) super(item) @score = score.to_f @parent = parent # Parsed now, unlike JobRecord: sidekiq-failures reopens this method and # reads @item straight after it. Measured on a 20k-member walk that reads # no field: 2.5us per entry at 250B, 5us at 2KB, 10us at 8KB, and nothing # at all for the walks that do read one, which is all of them in practice. self.item if @value end |
Instance Attribute Details
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
16 17 18 |
# File 'lib/wurk/sorted_entry.rb', line 16 def parent @parent end |
#score ⇒ Object (readonly)
Returns the value of attribute score.
16 17 18 |
# File 'lib/wurk/sorted_entry.rb', line 16 def score @score end |
Instance Method Details
#add_to_queue ⇒ Object
Removes this entry and re-enqueues it via the client with the payload
untouched. Backs the scheduled/dead "add to queue" actions — Sidekiq's
add_to_queue does not touch retry_count.
64 65 66 67 68 |
# File 'lib/wurk/sorted_entry.rb', line 64 def add_to_queue remove_job do || Client.new.push(Wurk.load_json()) end end |
#at ⇒ Object
39 |
# File 'lib/wurk/sorted_entry.rb', line 39 def at = ::Time.at(score).utc |
#delete ⇒ Object
Removes this entry from the parent set. Prefers exact-value match
(idempotent across duplicates with the same jid), falls back to
(score, jid) when constructed without a cached value.
44 45 46 47 48 49 50 |
# File 'lib/wurk/sorted_entry.rb', line 44 def delete if @value @parent.delete_by_value(@parent.name, @value) else @parent.delete_by_jid(@score, jid) end end |
#error? ⇒ Boolean
92 |
# File 'lib/wurk/sorted_entry.rb', line 92 def error? = !item['error_class'].nil? |
#id ⇒ Object
37 |
# File 'lib/wurk/sorted_entry.rb', line 37 def id = "#{score}|#{jid}" |
#kill ⇒ Object
Removes this entry from its parent set and writes it to the dead set. Death handlers fire with the synthesized "Job killed by API" exception (Sidekiq's default) so error trackers and the batch death path observe API/UI kills.
86 87 88 89 90 |
# File 'lib/wurk/sorted_entry.rb', line 86 def kill remove_job do || DeadSet.new.kill() end end |
#queue ⇒ Object
JobRecord resolves the queue eagerly and only from a pre-parsed Hash; a sorted-set entry is almost always built from the raw JSON string, so read it off the payload instead.
35 |
# File 'lib/wurk/sorted_entry.rb', line 35 def queue = @queue ||= item['queue'] |
#reschedule(at) ⇒ Object
Shifts the score by the delta to at, returning the new score like
Sidekiq's ZINCRBY does. ZADD XX INCR is that ZINCRBY minus its one
surprise: on a member already promoted or deleted it returns nil instead
of re-creating it, so a stale dashboard row can't resurrect a job that
has since run.
57 58 59 |
# File 'lib/wurk/sorted_entry.rb', line 57 def reschedule(at) Wurk.redis { |conn| conn.call('ZADD', @parent.name, 'XX', 'INCR', at.to_f - @score, value) } end |
#restore_after_failed_push ⇒ Object
Puts the original bytes back at the original score, after this entry was removed and its push failed. Internal: #remove_job and JobSet's batched retry_all, which removes a page before pushing it.
Past maxmemory the push is refused, and so is a plain ZADD putting the entry back. Dragonfly refuses both forms: all that is left is the log.
100 101 102 103 104 105 106 107 108 |
# File 'lib/wurk/sorted_entry.rb', line 100 def restore_after_failed_push Wurk.redis do |conn| conn.call('ZADD', @parent.name, @score, value) rescue RedisClient::OutOfMemoryError => e Fetcher::OomDrain.zadd(conn, e, @parent.name, @score, value) end rescue StandardError => e Wurk.logger.error("#{@parent.name} entry lost, ZADD refused (#{e.class}): #{loggable_payload}") end |
#retry ⇒ Object
Same flow but decrements retry_count first: the count was already
incremented when the job entered the retry set, and the next failure
bumps it again — without the decrement a manual "Retry now" would
consume an attempt. Wire-compat with Sidekiq's SortedEntry#retry.
74 75 76 77 78 79 80 |
# File 'lib/wurk/sorted_entry.rb', line 74 def retry remove_job do || job = Wurk.load_json() job['retry_count'] = job['retry_count'].to_i - 1 if job['retry_count'] Client.new.push(job) end end |