13

I have an APScheduler in a Flask app, sending events at some intervals.

Now i need to "refresh" all jobs, in fact just starting them now if they don't run without touching on the defined interval.

I'v tried to call job.pause() then job.resume() and nothing, and using job. reschedule_job(...) would trigger it but also change the interval... which i don't want.

My actual code is bellow:

cron = GeventScheduler(daemon=True)
# Explicitly kick off the background thread
cron.start()

cron.add_job(_job_time, 'interval', seconds=5, id='_job_time')
cron.add_job(_job_forecast, 'interval', hours=1, id='_job_forecast_01')

@app.route("/refresh")
def refresh():
    refreshed = []
    for job in cron.get_jobs():
         job.pause()
         job.resume()
         refreshed.append(job.id)
    return json.dumps( {'number': len(cron.get_jobs()), 'list': refreshed} )
dashie
  • 303
  • 1
  • 2
  • 11

4 Answers4

42

I discourage from calling job.func() as proposed in the accepted answer. The scheduler wouldn't be made aware of the fact that job is running and will mess up with the regular scheduling logic.

Instead use the job's modify() function to set its next_run_time property to now():

for job in scheduler.get_jobs():
    job.modify(next_run_time=datetime.now())

Also refer to the actual implementation of class Job.

Lars Blumberg
  • 19,326
  • 11
  • 90
  • 127
  • 1
    Do you know if changing next_run_time will interfere with the schedule? E.g. if the interval is x will the next run become x in the future from next_run_time when I modify it? – deed02392 Aug 22 '19 at 12:41
  • If I understand your question and APScheduler correctly, then the job should run _at the point in time_ which you specify with `next_run_time` (and not a predefined run interval after that point in time) – Lars Blumberg Aug 23 '19 at 14:18
  • 1
    Not quite my question. I have jobs I added with a set interval, and I am wondering if the previously planned next run (set by the interval) will be at all affected by modifying the next run time. I assume it will just mean the job won't run again until after `interval` has passed again? – deed02392 Aug 23 '19 at 14:22
  • 1
    Skimming over APScheduler's source code quickly, it indeed seems to work the way you describe it (scheduler will wait another interval after the manually triggered run). That's a transparent, straight forward approach. – Lars Blumberg Jun 25 '20 at 07:54
  • if the job is pause, this method will run the job immediately but change its status from pause to active. – ming Oct 12 '21 at 08:19
  • @ming then we could just test whether the job is paused and then skip it, couldn’t we? – Lars Blumberg Oct 13 '21 at 22:26
4

As a workaround i've done using the following. In summary i cycle through all jobs cron.get_jobs() and create a one-time job using Job object to a 'date' trigger, which only trigger once, at datetime.now since not specified.

def refresh():
    refreshed = []
    for job in cron.get_jobs():
        cron.add_job(job.func, 'date', id='{0}.uniq'.format(job.id), max_instances=1)
        refreshed.append(job.id)
    return json.dumps( {'number': len(cron.get_jobs()), 'list': refreshed} )
dashie
  • 303
  • 1
  • 2
  • 11
  • 1
    Also already 2 years ago, I've posted a new answer that will make user of the proper scheduling mechanisms to start a job _now_. – Lars Blumberg Aug 16 '17 at 08:03
1

Very late answer, but I think that what you need is to simply call the methods in your "refresh" route.

Daniel Bernal
  • 334
  • 3
  • 7
-5

You could just run the job function directly too.

for job in cron.get_jobs():
    job.func() 

If you had args or kwargs being passed into the function, you'd have to pull those out of job.args and/or job.kwargs. See apscheduler.job.Job

Everett Toews
  • 10,337
  • 10
  • 44
  • 45