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

How do I ensure that a the same job can't run twice? (unique job / avoid duplicates) #531

Closed
rgaufman opened this issue Feb 24, 2022 · 8 comments

Comments

@rgaufman
Copy link

I am looking for something like this for good_job: https://github.com/mhenrixon/sidekiq-unique-jobs

To be able to do specifically the equivalent of this:

sidekiq_options queue: :default, lock: :until_executed

Is this the equivalent with good_job? <

 good_job_control_concurrency_with(total_limit: 1, key: arguments)

Or am I misunderstanding?

@bensheldon
Copy link
Owner

Exactly. GoodJob's ActiveJob Concurrency extension can provide equivalent functionality to sidekiq-unique-jobs

This would be the equivalent of lock: :until_executed

class MyJob < ApplicationJob
  include GoodJob::ActiveJobExtensions::Concurrency

  good_job_control_concurrency_with(total_limit: 1)
  
  # ....
end

@rgaufman
Copy link
Author

Just to confirm:

  1. This allow many of the same job to run concurrently with different arguments
  2. But it won't allow queuing a new job if one is already running with the same arguments

Is that right?

@bensheldon
Copy link
Owner

Concurrency is limited based on whatever the key: value is. By default the key is the name of the class that the concurrency control is declared within, but you can use the lambda to make it based on anything (queue name, job arguments, some database call, anything) by using the Proc that returns a String that is compared against.

@rgaufman
Copy link
Author

Ah. ok, so then this should work and allow multiples of the same job, as long as arguments are different? (whatever the arguments are):

good_job_control_concurrency_with(total_limit: 1, key: arguments)

@bensheldon
Copy link
Owner

That exact code won't execute because arguments only exist in the context of a particular instance of a job. You'd need to stringify the arguments within a proc. e.g.

# an example scalpel based on your specific method signature
good_job_control_concurrency_with(total_limit: 1, key: -> { arguments[0] })

# or with a hammer
good_job_control_concurrency_with(total_limit: 1, key: -> { arguments.to_json })

@rgaufman
Copy link
Author

Why is .to_json necessary? - can I specify just arguments in the lambda?

@bensheldon
Copy link
Owner

You'll get whatever arguments.to_s stringifies to. Which is probably a consistent marshalling of the object, but I dunno. Give it a shot.

@rgaufman
Copy link
Author

Ah, understood, thank you!

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