diff --git a/README.md b/README.md index bc545f6..82abfb5 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,24 @@ class SynchronousJob < Gush::Job end ``` +### Skipping a Job + +Sometimes you'd like to skip a job, which doesn't mean that job/workflow has failed. You can call `skip!` inside the job to mark it as a `skipped`: + +```ruby +class ProcessUserJob < Gush::Job + def perform + user = User.find params[:id] + + skip! if user.processed? + + # Code beneath here will not be called anymore + # and the job will be marked as 'skipped' + # + # The workflow will continue on normally to the other jobs + end +end +``` ## Command line interface (CLI) diff --git a/lib/gush/job.rb b/lib/gush/job.rb index 9c0c962..6f21072 100644 --- a/lib/gush/job.rb +++ b/lib/gush/job.rb @@ -2,7 +2,7 @@ module Gush class Job attr_accessor :workflow_id, :incoming, :outgoing, :params, :finished_at, :failed_at, :started_at, :enqueued_at, :payloads, - :klass, :queue, :wait + :klass, :queue, :wait, :skipped_at attr_reader :id, :output_payload def initialize(opts = {}) @@ -20,6 +20,7 @@ def as_json finished_at: finished_at, enqueued_at: enqueued_at, started_at: started_at, + skipped_at: skipped_at, failed_at: failed_at, params: params, workflow_id: workflow_id, @@ -75,6 +76,11 @@ def fail! @finished_at = @failed_at = current_timestamp end + def skip! + @finished_at = @skipped_at = current_timestamp + throw(:skipped_job) + end + def enqueued? !enqueued_at.nil? end @@ -83,6 +89,10 @@ def finished? !finished_at.nil? end + def skipped? + !skipped_at.nil? + end + def failed? !failed_at.nil? end @@ -137,6 +147,7 @@ def assign_variables(opts) @workflow_id = opts[:workflow_id] @queue = opts[:queue] @wait = opts[:wait] + @skipped_at = opts[:skipped_at] end end end diff --git a/lib/gush/worker.rb b/lib/gush/worker.rb index 98cbd32..980bea4 100644 --- a/lib/gush/worker.rb +++ b/lib/gush/worker.rb @@ -18,7 +18,9 @@ def perform(workflow_id, job_id) mark_as_started begin - job.perform + catch(:skipped_job) do + job.perform + end rescue StandardError => error mark_as_failed raise error diff --git a/spec/features/integration_spec.rb b/spec/features/integration_spec.rb index 48a67d6..c9815fc 100644 --- a/spec/features/integration_spec.rb +++ b/spec/features/integration_spec.rb @@ -243,4 +243,49 @@ def configure expect(flow).to be_finished expect(flow).to_not be_failed end + + context 'when one of the jobs is skipped' do + it 'still runs the rest of the jobs in the workflow' do + SKIPPED_SPY = double() + + class FirstJob < Gush::Job + def perform + SKIPPED_SPY.foo + end + end + + class SkippedJob < Gush::Job + def perform + skip! + SKIPPED_SPY.bar + end + end + + class FinalJob < Gush::Job + def perform + SKIPPED_SPY.baz + end + end + + class PartiallySkippedWorkflow < Gush::Workflow + def configure + run FirstJob + run SkippedJob, after: FirstJob + run FinalJob, after: SkippedJob + end + end + + flow = PartiallySkippedWorkflow.create + flow.start! + + expect(SKIPPED_SPY).to receive(:foo) + perform_one + + expect(SKIPPED_SPY).not_to receive(:bar) + perform_one + + expect(SKIPPED_SPY).to receive(:baz) + perform_one + end + end end diff --git a/spec/gush/job_spec.rb b/spec/gush/job_spec.rb index eb3a971..3ca26d8 100644 --- a/spec/gush/job_spec.rb +++ b/spec/gush/job_spec.rb @@ -9,6 +9,7 @@ expect(job.output_payload).to eq("something") end end + describe "#fail!" do it "sets finished and failed to true and records time" do job = described_class.new(name: "a-job") @@ -21,6 +22,18 @@ end end + describe "#skip!" do + it "sets finished and skipped to true and records time" do + job = described_class.new(name: "a-job") + expect { job.skip! }.to throw_symbol(:skipped_job) + expect(job.skipped_at).to eq(Time.now.to_i) + expect(job.skipped?).to eq(true) + expect(job.finished?).to eq(true) + expect(job.running?).to eq(false) + expect(job.enqueued?).to eq(false) + end + end + describe "#finish!" do it "sets finished to false and failed to false and records time" do job = described_class.new(name: "a-job") @@ -123,6 +136,7 @@ outgoing: [], failed_at: nil, started_at: nil, + skipped_at: nil, finished_at: 123, enqueued_at: 120, params: {}, diff --git a/spec/gush/worker_spec.rb b/spec/gush/worker_spec.rb index 21c9c10..1470d8a 100644 --- a/spec/gush/worker_spec.rb +++ b/spec/gush/worker_spec.rb @@ -33,6 +33,33 @@ def configure end end + context "when job is skipped" do + it "should skip the rest of the code" do + class SkippedJob < Gush::Job + def perform + self.skip! + output = "Hello" + end + end + + class NormalWorkflow < Gush::Workflow + def configure + run SkippedJob + end + end + + workflow = NormalWorkflow.create + + subject.perform(workflow.id, "SkippedJob") + job = client.find_job(workflow.id, "SkippedJob") + + expect(job).to be_skipped + expect(job).to be_finished + expect(job.output_payload).not_to eq "Hello" + expect(job.output_payload).to be_nil + end + end + context "when job completes successfully" do it "should mark it as succedeed" do expect(subject).to receive(:mark_as_finished)