oveits / ProvisioningEngine

Ruby on Rails based ProvisioningEngine Frontend for provisioning of legacy systems via Apache Camel Backend (SOAP/XML+SPML+File import)
3 stars 6 forks source link

Create pull request for cancel functionality of Active Job #24

Open oveits opened 8 years ago

oveits commented 8 years ago

If MyJob < ActiveJob::Base and

myjob=MyJob.perform_later(...)

Then I have added functionality to cancel a job like follows:

myjob.cancel

without the need to jandle job providers like delayed_job or resque or sidekiq.

This functionality needs to be documented and best I should make a proposal to the Rails 5 team (best: a pull request).

oveits commented 8 years ago

Full patch file:

module ActiveJob
  # Provides behavior for enqueuing and retrying jobs.
  module Enqueuing
    extend ActiveSupport::Concern

    # Includes the +perform_later+ method for job initialization.
    module ClassMethods

      # Dequeues the job to be performed by the queue adapter. Only supported for Delayed::Jobs yet.
      #
      # ==== Examples
      #
      #    my_job_instance.dequeue
      #
      #def dequeue(options={})
      def dequeue()
        run_callbacks :dequeue do
          self.class.queue_adapter.dequeue self
        end
        self
      end

      # returns a list of all instances of the class GeneralJob
      # inspired by: http://stackoverflow.com/questions/6365638/how-to-get-class-instances-in-ruby
      # 
      # ==== Examples
      #
      #    GeneralJob.all
      #
      def all
        listall = []
        ObjectSpace.each_object GeneralJob do |thisjob|
          listall << thisjob
        end
        listall
      end # end def all
    end # module ClassMethods
  end # module Enqueuing

  module Execution

    # is removing the backend job (e.g. Delayed::Job), if it exists and sets the proper status
    #
    # * *Args*    : none
    # * *Returns* :
    #   - +true+ -> the provider_job was found and removed successfully
    #   - +false+ -> provider_job was not found 
    # * *Raises* :
    #   - +ArgumentError+ -> if number of arguments is not 0
    #
    def cancel
      self.class.queue_adapter.dequeue self
    end 
  end # module ExecutionOld

  module Core
    # ID optionally provided by adapter
    attr_accessor :provider_job_id
  end

  module QueueAdapters
    class DelayedJobAdapter
      class << self
        def enqueue(job) #:nodoc:
          delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name)
          job.provider_job_id = delayed_job.id
          delayed_job
        end

        def enqueue_at(job, timestamp) #:nodoc:
          delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, run_at: Time.at(timestamp))
          job.provider_job_id = delayed_job.id
          delayed_job
        end

        # is removing the backend job (e.g. Delayed::Job), if it exists and sets the proper status
        #
        # * *Args*    : none
        # * *Returns* :
        #   - +true+ -> the provider_job was found and removed successfully
        #   - +false+ -> provider_job was not found 
        # * *Raises* :
        #   - +ArgumentError+ -> if number of arguments is not 0
        #   - +Abort+ -> in case there were more than 1 delayed jobs found for this ActiveJob (points to a bug, if it happens)
        #
        def dequeue(job)
          provider_jobs = Delayed::Job.where(id: job.provider_job_id)
          case provider_jobs.count
          when 1
            provider_jobs[0].delete
            true
          when 0
            false
          else
            abort "There are more than one Delayed::Job.where(id: #{job.provider_job_id}). This should never happen and it looks like a bug."
          end
        end
      end

      class JobWrapper #:nodoc:
        attr_accessor :job_data

        def initialize(job_data)
          @job_data = job_data
        end

        def perform
          Base.execute(job_data)
        end
      end
    end
  end
end