Skip to content
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
13 changes: 12 additions & 1 deletion lib/gush/job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {})
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -83,6 +89,10 @@ def finished?
!finished_at.nil?
end

def skipped?
!skipped_at.nil?
end

def failed?
!failed_at.nil?
end
Expand Down Expand Up @@ -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
4 changes: 3 additions & 1 deletion lib/gush/worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
45 changes: 45 additions & 0 deletions spec/features/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 14 additions & 0 deletions spec/gush/job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")
Expand Down Expand Up @@ -123,6 +136,7 @@
outgoing: [],
failed_at: nil,
started_at: nil,
skipped_at: nil,
finished_at: 123,
enqueued_at: 120,
params: {},
Expand Down
27 changes: 27 additions & 0 deletions spec/gush/worker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down