Keep SortedEntry's in-memory score in sync after reschedule by hammadxcm · Pull Request #7017 · sidekiq/sidekiq · GitHub
Skip to content

Keep SortedEntry's in-memory score in sync after reschedule - #7017

Merged
mperham merged 1 commit into
sidekiq:mainfrom
hammadxcm:fix-sorted-entry-reschedule-score
May 29, 2026
Merged

mperham merged 1 commit into
sidekiq:mainfrom
hammadxcm:fix-sorted-entry-reschedule-score

Conversation

@hammadxcm

Copy link
Copy Markdown
Contributor

Summary

Sidekiq::SortedEntry#reschedule writes the new score to Redis via zincrby but never updates @score, so the in-memory entry's #score and #at keep returning the stale (pre-reschedule) values:

entry = Sidekiq::ScheduledSet.new.first   # score => T0
entry.reschedule(Time.at(T0 + 500))
entry.score   # => T0 (stale, redis has T0+500)
entry.at      # => Time.at(T0) (stale)

The other SortedEntry mutators (add_to_queue/retry/kill/delete) all remove the entry from its set, so a stale entry there is moot. reschedule is the only mutator that keeps the job alive in the same set with a new score — making the drift between in-memory state and Redis a real footgun specifically here.

Fix: set @score = at.to_f after the zincrby.

Testing

Adds a focused regression test that re-reads entry.score / entry.at after reschedule and asserts they reflect the new time. Fails before the change and passes after. The existing "can reschedule jobs" test is unaffected (it re-iterates the set, so it always sees fresh entries from Redis).

bundle exec rake is green (standard + lint:herb + full suite).

SortedEntry#reschedule writes the new score to Redis via zincrby but
never updates @score, so the in-memory entry returns the stale (pre-
reschedule) value from #score and #at. Other SortedEntry mutators
(add_to_queue/retry/kill/delete) remove the entry from its set, so a
stale entry there is moot — but reschedule keeps the job in the same
set with a new score, making the drift between in-memory state and
Redis a real footgun:

  entry = Sidekiq::ScheduledSet.new.first
  entry.reschedule(Time.now + 500)
  entry.score   # => stale (the original score)
  entry.at      # => stale

Set @score = at.to_f after the zincrby. Adds an api_test that fails
before the change and passes after; existing reschedule test still
passes because it re-iterates the set (fresh entries from Redis).
@mperham
mperham merged commit fcb71fc into sidekiq:main May 29, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants