Module: TrackableJob

Overview

This is a mix-in that allows jobs to be trackable. Trackable jobs can be queried at /jobs/. A client requesting HTML would see a progress bar; a client requesting JSON will get a status message. When the job is complete, the trackable job can specify a path to redirect the user to.

To use this mix-in, implement +perform_tracked+ instead of +perform+, with the same arguments. If you intend to use +rescue_from+ and you wish for the job to fail, call +rescue_tracked+ with the exception.

Jobs are ephemeral; do not expect jobs to remain after a long period of time. Also since jobs are uniquely identified only by ID and do not need authentication, do not leak anything sensitive from the job.

Defined Under Namespace

Classes: Job

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#jobObject (readonly)

Returns the value of attribute job


42
43
44
# File 'lib/autoload/trackable_job.rb', line 42

def job
  @job
end

Instance Method Details

#initialize(*args) ⇒ Object

Implements +initialize+, creating or loading the job from the database.


55
56
57
58
59
# File 'lib/autoload/trackable_job.rb', line 55

def initialize(*args)
  super

  @job = Job.find_or_initialize_by(id: job_id)
end

#job_id=(job_id) ⇒ Object


69
70
71
72
73
74
# File 'lib/autoload/trackable_job.rb', line 69

def job_id=(job_id)
  super.tap do
    next unless @job
    @job = find_job(job_id)
  end
end

#perform(*args) ⇒ Object


61
62
63
64
65
66
67
# File 'lib/autoload/trackable_job.rb', line 61

def perform(*args)
  logger.debug(message: 'Perform job', id: @job&.id)
  perform_tracked(*args)
  logger.debug(message: 'Finish performing job', id: @job&.id)
  @job.status = :completed
  @job.save!
end

#perform_trackedObject (protected)

Raises:

  • (NotImplementedError)

78
79
80
# File 'lib/autoload/trackable_job.rb', line 78

def perform_tracked(*)
  raise NotImplementedError
end

#rescue_tracked(exception) ⇒ Object (protected)


82
83
84
85
86
87
88
89
# File 'lib/autoload/trackable_job.rb', line 82

def rescue_tracked(exception)
  @job.status = :errored
  error = { class: exception.class.name, message: exception.to_s, backtrace: exception.backtrace }
  error.merge!(exception.try(:to_h) || {})

  @job.error = error
  @job.save!
end

#wait(timeout = nil) ⇒ Object

Waits for the asynchronous job to finish.

Parameters:

  • timeout (Integer) (defaults to: nil)

    The amount of time to wait.

Raises:

  • (Timeout::Error)

    If the timeout was elapsed without the condition being met.


48
49
50
51
52
# File 'lib/autoload/trackable_job.rb', line 48

def wait(timeout = nil)
  wait_result = job.wait(timeout: timeout, while_callback: -> { job.tap(&:reload). })

  raise Timeout::Error if wait_result.nil?
end