Call job asynchronously and see it in Running status
Closed this issue · 12 comments
I would like to ask two questions regarding the call method for a job.
-
I noticed the job is not running when
call
is called. On the other hand if it is scheduled and is executing, the methodrunning?
returns TRUE as it is supposed to be. Is there a way to get the job result asrunning? == TRUE
? -
Is there a way to call the job in a non-blocking way?
Explaining: I keep all my schedule-able jobs in a database and I call them Tasks.
I have a RailsTask
model and whenever I want the user to interact with it I have an API to edit a column of Task calledaction
. Whenever i want have the user "kill", "schedule", "call", "pause" a job, I just let the user write the action in theaction
column.
Saving the record will trigger a Rails after_commit
hook that will execute the associated Rufus method. The problem is that for long lasting job, whenever I execute the method call
, the thread serving the user hangs there until the job ends running. The problem is that after 20 seconds the API call times out and the user gets an error.
What I would like to do is for the user to call and don't wait for the job to end. Also I would like for the user to see that the job in a running status (see point 1.)
Hello,
would that help?
require 'rufus-scheduler'
s = Rufus::Scheduler.new
j =
s.schedule_every '10m' do
puts 'in...'
sleep 3
puts 'out.'
end
#Thread.new { j.call }
Thread.new { j.trigger(Time.now) }
sleep 1
puts "running? #{j.running?}"
s.join
It should answer your two questions.
I could provide a #trigger_call
to avoid the Time.now
:
def trigger_call
trigger(Time.now)
end
gonna try it out man thanks for the fast reply.
I'll let you know as soon as I have feedback to give.
It seems to work but there is still one thing I don't understand:
before calling trigger
I need to schedule the job (which I don't really want, but I have to in order to have a Job instance - right?!). The problem is that my idea of call/trigger
is "run it once and that's it" - The user can call a job even though it is not really scheduled to repeat itself. So what i do in my application is to:
- Schedule
- Call/Trigger
- Kill
Now, I have the code as follow:
Thread.new do
task.job.trigger(Time.now)
# if the job was scheduled only for it to be called once, kill it.
# otherwise keep it scheduled
if (need_to_kill)
task.kill(true)
end
end
the above code triggers the job, but then it seems to be killed right away, like trigger is a non-blocking command. I would expect the if (need_to_kill)
part to be executed only after the job ended its execution.
By the way if I comment that if (need_to_kill)
part job runs nicely and running?
is TRUE. Thanks!
before calling trigger I need to schedule the job (which I don't really want, but I have to in order to have a Job instance - right?!)
Then, why are you using rufus-scheduler? Why don't you use a simple job queue library without scheduling?
Anyway, this could work:
require 'rufus-scheduler'
s = Rufus::Scheduler.new
j =
s.schedule_at Time.now + 24 * 3600 do # in 1 day
puts 'in...'
sleep 2
puts 'out.'
end
puts "jobs: #{s.jobs.size}"
#Thread.new { j.call }
Thread.new { j.trigger(Time.now) }
sleep 1
puts "running? #{j.running?}"
sleep 3
puts "jobs: #{s.jobs.size}"
s.join
The at
triggers only once, and the example forces the trigger "asap", that "consumes" the job.
I hope this will help.
Just to clarify, For each of my task the user can:
- enable/disable task: this is just a boolean flag for me to auto-schedule or not all my task on application boot. (first icon)
- schedule: the regular job schedule.
- pause: pausing a job that is running.
- kill: stopping a running job.
- call: calling any job once, without the need for the task to be scheduled.
Statuses on the left are (left to right):
- enabled?
- scheduled?
- running?
- paused?
The image may clarifies:
Does it make sense?
Does it make sense?
It does make sense.
Didn't mean to be arrogant, the words I choose sometimes are not very clear to other people, was only trying to prove that I was using this awesome tool the correct way (hopefully).
Is still the above suggestion the best way to get the job done?
Thanks again for all the support.
Hello,
I did not feel any arrogance out of you. You said thanks multiple times and simple "thanks" are becoming rare. Mi fa tanto piacere.
Thanks for clarifying your purpose. I'm always narrowing on what people write, in order to force them to re-phrase. I am sure you are using this technique with your customers or project managers ;-)
Here is a suggestion that triggers and unschedules, it might serve your purpose for whatever schedule type:
require 'rufus-scheduler'
s = Rufus::Scheduler.new
j =
s.schedule_every '10m' do
puts 'in...'
sleep 2
puts 'out.'
end
puts "jobs: #{s.jobs.size}"
#Thread.new { j.call }
Thread.new {
j.trigger(Time.now)
Thread.pass # else it won't trigger
j.unschedule
}
sleep 1
puts "running? #{j.running?}"
sleep 3
puts "jobs: #{s.jobs.size}"
s.join
Mi fa tanto piacere.
Lol. How did you know I was Italian? or, did you?
Your name is Italian, your website has pieces in Italian. It was not hard to guess ;-)
Are your questions all answered?
Lol I see. Yes everything works just perfect. Thanks for helping out.
Thanks to you!