module CanvasSync::JobUniqueness module UniqueJobCommon extend ActiveSupport::Concern included do class_attribute :unique_job_options, instance_writer: false end class_methods do # ensure_uniqueness( # strategy: :until_executed, # :until_executed, :until_executing, :until_expired, :until_and_while_executing, :while_executing # on_conflict: :raise, # :raise, :log, :reject, :reschedule, { enqueue: ..., perform: ... }, proc # lock_ttl: 7.days, # seconds # lock_timeout: 0, # seconds # scope: :per_queue, # :global, :per_queue, string ("-"), proc # hash: ->{ { ... } }, # # In the case of UntilExecuted and WhileExecuting, how should the execution lock be released in an error condition? # # :any - Release the lock when the Job's (implicit) Batch is :complete # # :death - Release the lock when the Job's Batch receives the :death callback # # :stagnant - Release the lock when the Job's Batch receives the :stagnant callback # # :expire - Do not release the lock until it expires # unlock_on_failure: :stagnant, # ) def ensure_uniqueness(**kwargs) if self.unique_job_options.present? raise ArgumentError, "ensure_uniqueness can only be called once per job class" end begin require "sidekiq_unique_jobs" rescue LoadError raise LoadError, "sidekiq-unique-jobs is required for ensure_uniqueness" end OnConflict.validate!(kwargs[:on_conflict], kwargs[:strategy]) if kwargs[:on_conflict].present? kwargs[:scope] ||= :per_queue kwargs[:ttl] ||= 30.days.to_i kwargs[:timeout] ||= 0 kwargs[:limit] ||= 1 self.unique_job_options = kwargs include UniqueJobMethods end end module UniqueJobMethods extend ActiveSupport::Concern class_methods do def unlock!(jid = nil, args: nil, kwargs: nil, queue: nil) queue = self.try(:default_queue_name) || try(:queue) raise ArgumentError, "Must specify queue:" unless queue.is_a?(String) || queue.is_a?(Symbol) temp_context = LockContext.new({ job_clazz: self, jid: jid, queue: queue, args: args, kwargs: kwargs }) strategy = temp_context.lock_strategy locksmith = strategy.send(:locksmith) if jid locksmith.unlock!() else locksmith.locked_jids.each do |jid| unlock!(jid, args: args, kwargs: kwargs, queue: queue) end end end # def unlock_all!(queue: :all) # # TODO Public API to manually remove all locks for this class # end end end end end