Scheduling a shutdown
itsaphel opened this issue · 9 comments
Hey.
So I have a main thread that creates a new thread with my Rufus scheduler code. In this new thread, I create a schedule, schedule a cron job, schedule a shutdown, and then join the scheduler. When I shutdown, I want all currently running tasks to first finish (but not currently running ones not to start). If I understand correctly, this is done using .schedule(:wait)
.
Something like this:
def run
scheduler = Rufus::Scheduler.new
scheduler.cron "* * * * *" do |job|
sleep 65
puts "Done!"
end
scheduler.in "2m" do
puts "#{Time.now} Shutdown initiated"
scheduler.shutdown(:wait)
puts "#{Time.now} Scheduler stopped"
end
scheduler.join
end
So basically, with this I'd expect to see two "Done!"s, with the second job starting before the shutdown starts (and currently running at the time of shutdown), so the shutdown waiting for that job to be finished. Example output may be:
2020-11-01 20:00:05 +0000 Done!
2020-11-01 20:00:34 +0000 Shutdown initiated
2020-11-01 20:01:05 +0000 Done!
2020-11-01 20:01:05 +0000 Scheduler stopped
Instead I get either an error (saying that I cannot do :wait on the same thread), or it just doesn't do anything and shuts down as if :wait wasn't there (when I comment out the sleep 65 I get an error, when I leave it in it just stops as if :wait wasn't there). When I get the error, it is:
2500 Rufus::Scheduler::InJob "2m" {:no_error=>true, :_t=>120}
2500 error:
2500 2500
2500 ThreadError
2500 Target thread must not be current thread
[...]
2500 work_threads: 1
2500 active: 1
2500 vacant: 0
2500 max_work_threads: 28
2500 mutexes: {}
2500 jobs: 0
2500 at_jobs: 0
2500 in_jobs: 0
2500 every_jobs: 0
2500 interval_jobs: 0
2500 cron_jobs: 0
2500 running_jobs: 1
2500 work_queue: 1
Any idea how I can achieve what I'm trying to do here?
More details about the error:
{ 1474578217680 rufus-scheduler intercepted an error:
1474578217680 job:
1474578217680 Rufus::Scheduler::InJob "2m" {:no_error=>true, :_t=>120}
1474578217680 error:
1474578217680 1474578217680
1474578217680 ThreadError
1474578217680 Target thread must not be current thread
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler.rb:525:in `join'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler.rb:525:in `block in join_all_work_threads'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler.rb:525:in `each'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler.rb:525:in `join_all_work_threads'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler.rb:127:in `shutdown'
1474578217680 variant1.rb:16:in `block in run'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler/jobs.rb:223:in
`do_call'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler/jobs.rb:267:in
`trigger_now'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler/jobs.rb:312:in
`block (3 levels) in start_work_thread'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler/jobs.rb:315:in
`block (2 levels) in start_work_thread'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler/jobs.rb:301:in
`loop'
1474578217680 /home/jmettraux/.gem/ruby/2.6.6/gems/rufus-scheduler-3.6.0/lib/rufus/scheduler/jobs.rb:301:in
`block in start_work_thread'
Hello,
I think I have it fixed. I will release a new version of the gem as soon as possible. Feel free to try the fix and tell me here if there are still problems.
One comment, I think you don't need a separate thread for just launching the scheduler, the scheduler already has its own thread. You simply have to instantiate the scheduler from your main thread and schedule. Those calls return immediately and you're free to do your main thing in your main thread.
Best regards and thanks for pointing at this issue.
@jmettraux Hey! Thanks, this fixes the error, but still doesn't achieve what I was trying to in my initial post.
The output now is:
2020-11-02 12:52:06 +0000 Done! Next run starts: 2020-11-02 12:53:00 +0000
2020-11-02 12:52:42 +0000 Shutdown initiated
2020-11-02 12:52:42 +0000 Scheduler stopped
Whereas there should be an extra "Done!" after the shutdown is initiated (reason being: two of those jobs will be initiated to start before the shutdown in 2 minutes actually starts. I would like the started job to complete before shutdown).
I tried being creative and adding the shutdown schedule into a shutdown_scheduler which shuts down the main scheduler, then joining both schedulers.
This worked a little better (it actually waits for the task to finish, it seems), but upon shutdown it also seems to run the task again, so the task runs 3 times instead of 2 (expected). Strange, because in the above example it runs only 1 time (instead of 2). Take this result with a grain of salt, though, I may be doing something weird.
Hello,
OpenBSD yawara 6.8 GENERIC.MP#0 amd64
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-openbsd6.7]
Gems included by the bundle:
* concurrent-ruby (1.1.7)
* et-orbi (1.2.4)
* fugit (1.4.0)
* raabro (1.4.0)
* rufus-scheduler (3.7.0)
* tzinfo (2.0.2)
require 'rufus-scheduler'
$stdout.sync = true
scheduler = Rufus::Scheduler.new
scheduler.cron '* * * * *' do |job|
c = job.count
puts "#{Time.now} #{job.id} starting... #{c}"
sleep 65
puts "#{Time.now} #{job.id} done. #{c}"
end
scheduler.in '2m' do |job|
puts "#{Time.now} Shutdown initiated (#{job.id})"
scheduler.shutdown(:wait)
puts "#{Time.now} Scheduler stopped (#{job.id})"
end
puts "#{Time.now} joining..."
scheduler.join
puts "#{Time.now} over."
#$stdout.flush
is giving me
2020-11-02 23:47:15 +0900 joining...
2020-11-02 23:48:00 +0900 cron_1604328435.977129_232882975720 starting... 1
2020-11-02 23:49:00 +0900 cron_1604328435.977129_232882975720 starting... 2
2020-11-02 23:49:05 +0900 cron_1604328435.977129_232882975720 done. 1
2020-11-02 23:49:05 +0900 cron_1604328435.977129_232882975720 starting... 3
2020-11-02 23:49:16 +0900 Shutdown initiated (in_1604328435.9790182_0.0_231526836820)
2020-11-02 23:49:16 +0900 over.
It's quite similar to what you are reporting. I will investigate further tomorrow morning.
Hello @itsaphel,
I've just pushed changes to `Scheduler#shutdown'. I think it's right now. If you could give it a try, that'd be much appreciated.
OpenBSD yawara 6.8 GENERIC.MP#1 amd64
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-openbsd6.7]
require 'rufus-scheduler'
$stdout.sync = true
def now; Time.now.strftime('%F %T.%L'); end
scheduler = Rufus::Scheduler.new
scheduler.cron '* * * * *' do |job|
c = job.count
puts "#{now} #{job.id} starting... #{c}"# #{Thread.current}"
sleep 65
puts "#{now} #{job.id} done. #{c}"# #{Thread.current}"
end
scheduler.in '2m' do |job|
puts "#{now} Shutdown initiated (#{job.id})"# #{Thread.current}"
scheduler.shutdown(:wait)
puts "#{now} Scheduler stopped (#{job.id})"# #{Thread.current}"
end
puts "#{now} joining..."
puts
scheduler.join
puts "#{now} over."
puts
2020-11-05 14:43:34.790 joining...
2020-11-05 14:44:00.207 cron_1604555014.7889805_1309232740140 starting... 1
2020-11-05 14:45:00.047 cron_1604555014.7889805_1309232740140 starting... 2
2020-11-05 14:45:05.215 cron_1604555014.7889805_1309232740140 done. 1
2020-11-05 14:45:05.317 cron_1604555014.7889805_1309232740140 starting... 3
2020-11-05 14:45:35.087 Shutdown initiated (in_1604555014.790724_0.0_1309924421900)
2020-11-05 14:46:05.056 cron_1604555014.7889805_1309232740140 done. 2
2020-11-05 14:46:10.334 cron_1604555014.7889805_1309232740140 done. 3
2020-11-05 14:46:10.426 Scheduler stopped (in_1604555014.790724_0.0_1309924421900)
2020-11-05 14:46:10.426 over.
Will try test again.
Question, in your output log why is a cron 3 starting? FWIW, I was getting this in my earlier tests as well when I used a separate scheduler to schedule the shutdown (hence avoiding the error); I was a bit puzzled by it:
The cron should start at 14:44:00, 14:45:00, 14:46:00, etc, right? Cron 1 and 2 start as normal, but cron 3 is started 5 seconds after 2 is started (at 14:45:05).
Other than that, your log looks okay to me, but I'd have imagined there should be only two cron jobs starting (one at 14:44:00, two at 14:45:00, then shutdown initiated at 14:45:35 so the cron 3 scheduled for 14:46:00 never starts).
The cron should start at 14:44:00, 14:45:00, 14:46:00, etc, right? Cron 1 and 2 start as normal, but cron 3 is started 5 seconds after 2 is started (at 14:45:05).
Yes, you are right. I will fix that now.
2020-11-07 08:20:53.105 joining...
2020-11-07 08:21:00.243 cron_1604704853.103283_1569905716380 starting... 1
2020-11-07 08:22:00.114 cron_1604704853.103283_1569905716380 starting... 2
2020-11-07 08:22:05.252 cron_1604704853.103283_1569905716380 done. 1
2020-11-07 08:22:53.203 Shutdown initiated (in_1604704853.1050184_0.0_1570668441160)
2020-11-07 08:23:05.122 cron_1604704853.103283_1569905716380 done. 2
2020-11-07 08:23:05.293 Scheduler stopped (in_1604704853.1050184_0.0_1570668441160)
2020-11-07 08:23:05.293 over.
I think I nailed that second problem. Please tell me if you have anything else.
Thanks a lot!