Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Request] sidekiq-cron-like enqueue guarantee #6180

Open
arthurchui opened this issue Jan 31, 2024 · 1 comment
Open

[Request] sidekiq-cron-like enqueue guarantee #6180

arthurchui opened this issue Jan 31, 2024 · 1 comment

Comments

@arthurchui
Copy link

In a recent incident, a mission-critical daily cron was skipped because a leader just stepped down and a new leader was elected 40s later. According to the document of Ent Periodic Jobs, it is the expected behaviour:

This implementation does not support backfill. If Sidekiq is shutdown, it will not create jobs for the times missed on restart. I advise people to make their cron jobs resilient to timing. Instead of having an hourly job which processes only the last hour of data, make it process the last N hours.

However in our case, the task can't wait 24 hours till the next job runs. Alternatively, instead of running a daily job, we can run an hourly job that checks if the task has been done for the day. However it feels like a wrong paradigm for a task that is only executed once per day.

The gem sidekiq-cron records the last enqueue time and the poller guarantees to run a cron if the corresponding job hasn't been enqueued at the expected time. Can sidekiq-ent implement a similar feature for missing critical crons?

Possibly not all crons need the guarantee. An attribute reliable: true can be provided when it is mission critical:

  config.periodic do |mgr|
    mgr.register('0 * * * *', "SomeHourlyWorkerClass")
    mgr.register('* * * * *', "DailyDigestJob", reliable: true)
  end

Thoughts?

@mperham
Copy link
Collaborator

mperham commented Jan 31, 2024

Something like this?

sidekiq_options retry: 0

# schedule frequently, runs daily
def perform(...)
  return "already done" if Sidekiq.redis { |c| c.get("my-lock") }
  # do work
  Sidekiq.redis { |c| c.set("my-lock", Time.now.to_s, "ex", 86400, "nx") }
end

Now I could wrap this functionality and expose it but three lines seems a minimal cost and you could wrap that into one helper method or module.

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

No branches or pull requests

2 participants