Skip to content

Commit

Permalink
Allow TimerTask to be safely restarted after shutdown and avoid dupli…
Browse files Browse the repository at this point in the history
…cate tasks

Creates a new @running object on shutdown while the ScheduledTask is checking the previously set @running object which will remain false
  • Loading branch information
bensheldon authored and ioquatix committed Nov 14, 2023
1 parent 25ccddc commit f3d097c
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
8 changes: 5 additions & 3 deletions lib/concurrent-ruby/concurrent/timer_task.rb
Expand Up @@ -278,24 +278,26 @@ def ns_initialize(opts, &task)
# @!visibility private
def ns_shutdown_execution
@running.make_false
@running = Concurrent::AtomicBoolean.new(false)
super
end

# @!visibility private
def ns_kill_execution
@running.make_false
@running = Concurrent::AtomicBoolean.new(false)
super
end

# @!visibility private
def schedule_next_task(interval = execution_interval)
ScheduledTask.execute(interval, args: [Concurrent::Event.new], &method(:execute_task))
ScheduledTask.execute(interval, args: [Concurrent::Event.new, @running], &method(:execute_task))
nil
end

# @!visibility private
def execute_task(completion)
return nil unless @running.true?
def execute_task(completion, continue_running)
return nil unless continue_running.true?
_success, value, reason = @executor.execute(self)
if completion.try?
self.value = value
Expand Down
15 changes: 14 additions & 1 deletion spec/concurrent/timer_task_spec.rb
@@ -1,5 +1,6 @@
require_relative 'concern/dereferenceable_shared'
require_relative 'concern/observable_shared'
require 'concurrent/atomic/atomic_fixnum'
require 'concurrent/timer_task'

module Concurrent
Expand Down Expand Up @@ -94,12 +95,24 @@ def trigger_observable(observable)
end

context '#shutdown' do

it 'returns true on success' do
task = TimerTask.execute(run_now: false) { nil }
sleep(0.1)
expect(task.shutdown).to be_truthy
end

it 'will cancel pre-shutdown task even if restarted to avoid double-runs' do
counter = Concurrent::AtomicFixnum.new(0)
task = TimerTask.execute(execution_interval: 0.2, run_now: true) { counter.increment }
sleep 0.05
expect(counter.value).to eq 1

task.shutdown
task.execute

sleep 0.25
expect(counter.value).to eq 3
end
end
end

Expand Down

0 comments on commit f3d097c

Please sign in to comment.