Schdeuling jobs after calling .start() APscheduler - python

I am writing a program to schedule and cancel alarms in Flask. I am using the apscheduler library for the timings.
I need to be able to add events to the job queue at any point, so I need to be able to add events after the scheduler is run.
Currently, I have:
from apscheduler.schedulers.background import BackgroundScheduler
def cancel():
job = events[0]
job.remove()
def schedule():
sched = scheds[0]
try:
sched.shutdown()
except:
pass
job = sched.add_job(my_job, 'date', run_date=t, args=['text'])
events.append(job)
sched.start()
def schedule2():
sched = scheds[0]
try:
sched.shutdown()
except:
pass
job = sched.add_job(my_job, 'date', run_date=t2, args=['text'])
events.append(job)
sched.start()
Where scheds is an array to store a global scheduler, and events is an array which stores the events that are scheduled.
I need to run schedule, then schedule2, to schedule two different jobs. When I try this, I get an error which says that I cannot run schedule2 because the 'scheduler is already running'. How can I achieve this?

Related

Python, schedule parallel Threads with one thread for each method

How I can run those two tasks in parallel, but if the Thread with the name of the method was not finished yet just skip this method till the next schedule iteration?
Because now it creates a new thread for the same method while it is running.
def task1:
#do task1
def task1:
#do task2
def run_threaded(job_fn):
job_thread = threading.Thread(target=job_fn)
job_thread.start()
schedule.every(5).minutes.do(run_threaded, task1)
schedule.every(3).minutes.do(run_threaded, task2)
while True:
schedule.run_pending()
time.sleep(1)
Figured out with another module called apscheduler.
It has parameter max_instances:1 and log thing like this
*Execution of job "task1 (trigger: interval[0:50:0], next run at: 2019-02-16 11:38:23 EET)" skipped: maximum number of running instances reached (1)*
scheduler = BackgroundScheduler(executors=executors, job_defaults=job_defaults)
scheduler.add_job(task1, 'interval', minutes=5)
scheduler.add_job(task2, 'interval', minutes=7)
scheduler.start()
You don't need to create a threading.Thread because module doing this for you. Just pass your method.

Run schedule function in new thread

I used the schedule library to schedule a function every X seconds:
Want I want is to run this function on separate thread. I found this in the documentation on how to Run the scheduler in a separate thread but I didn't understand what he did.
Is there someone who can explain to me how to do that ?
Update:
This what I tried:
def post_to_db_in_new_thread():
schedule.every(15).seconds.do(save_db)
t1 = threading.Thread(target=post_to_db_in_new_thread, args=[])
t1.start()
You don't really need to update schedule in every task
import threading
import time
import schedule
def run_threaded(job_func):
job_thread = threading.Thread(target=job_func)
job_thread.start()
schedule.every(15).seconds.do(run_threaded, save_db)
while 1:
schedule.run_pending()
time.sleep(1)

Can we add jobs to running schedular in ApSchedular

I started Background scheduler in one file and ran it. Then from other file I accessed scheduler instance and added job. What my thought was the instance will add the job and it will run. I am new to this scheduling mechanisms. What I did is
On one file Main.py
import time
from apscheduler.schedulers.background import BackgroundScheduler
class Main:
a = 2
sched = BackgroundScheduler()
sched.start()
while True:
time.sleep(5)
From other file Bm.py
from Main import Main
class Bm(Main) :
def timed_job():
print 'aa'
Main.sched.add_job(timed_job,'interval',seconds=1)
I thought this would do, but it didnot.I need to this way from seperate file because I need to make a task manager which would run jobs and I need to be able to add or remove jobs anytime needed.SO how can we add and remove jobs to/from running apscheduler?
UPDATE :
This is confusing. I added a function printme on Main.py and did sched.add_job(printme,'interval',seconds=5), it prints me as expected but when I run Bm.py it also prints me, when it was supposed to print aa
def printme():
print 'me'
while True:
# time.sleep(5)
sched.add_job(printme,'interval',seconds=5)
if (input() is 'q'):
sched.shutdown()

Python - Apscheduler not stopping a job even after using 'remove_job'

This is my code
I'm using the remove_job and the shutdown functions of the scheduler to stop a job, but it keeps on executing.
What is the correct way to stop a job from executing any further?
from apscheduler.schedulers.background import BlockingScheduler
def job_function():
print "job executing"
scheduler = BlockingScheduler(standalone=True)
scheduler.add_job(job_function, 'interval', seconds=1, id='my_job_id')
scheduler.start()
scheduler.remove_job('my_job_id')
scheduler.shutdown()
Simply ask the scheduler to remove the job inside the job_function using the remove_function as #Akshay Pratap Singh Pointed out correctly, that the control never returns back to start()
from apscheduler.schedulers.background import BlockingScheduler
count = 0
def job_function():
print "job executing"
global count, scheduler
# Execute the job till the count of 5
count = count + 1
if count == 5:
scheduler.remove_job('my_job_id')
scheduler = BlockingScheduler()
scheduler.add_job(job_function, 'interval', seconds=1, id='my_job_id')
scheduler.start()
As you are using BlockingScheduler , so first you know it's nature.
So, basically BlockingScheduler is a scheduler which runs in foreground(i.e start() will block the program).In laymen terms, It runs in the foreground, so when you call start(), the call never returns. That's why all lines which are followed by start() are never called, due to which your scheduler never stopped.
BlockingScheduler can be useful if you want to use APScheduler as a standalone scheduler (e.g. to build a daemon).
Solution
If you want to stop your scheduler after running some code, then you should opt for other types of scheduler listed in ApScheduler docs.
I recommend BackgroundScheduler, if you want the scheduler to run in the background inside your application/program which you can pause, resume and remove at anytime, when you need it.
The scheduler needs to be stopped from another thread. The thread in which scheduler.start() is called gets blocked by the scheduler. The lines that you've written after scheduler.start() is unreachable code.
This is how I solved the problem. Pay attention to the position where the code schedule.shutdown() is located!
def do_something():
global schedule
print("schedule execute")
# schedule.remove_job(id='rebate')
schedule.shutdown(wait=False)
if __name__ == '__main__':
global schedule
schedule = BlockingScheduler()
schedule.add_job(do_something, 'cron', id='rebate', month=12, day=5, hour=17, minute=47, second=35)
schedule.start()
print('over')

How do I schedule an interval job with APScheduler?

I'm trying to schedule an interval job with APScheduler (v3.0.0).
I've tried:
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
def my_interval_job():
print 'Hello World!'
sched.add_job(my_interval_job, 'interval', seconds=5)
sched.start()
and
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
#sched.scheduled_job('interval', id='my_job_id', seconds=5)
def my_interval_job():
print 'Hello World!'
sched.start()
Either should work according to the docs, but the job never fires...
UPDATE:
It turns out there was something else, environment-related, preventing the task from running. This morning, the task is working fine without any modifications to the code from yesterday.
UPDATE 2:
After further testing, I've found that 'interval' jobs seem to be generally flaky... The above code now works in my dev environment, but not when I deploy to a staging env (I'm using a heroku app for staging). I have other apscheduler 'cron' jobs that work just fine in the staging/production envs.
When I turn on DEBUG logging for the "apscheduler.schedulers" logger, the log indicates that the interval job is added:
Added job "my_cron_job1" to job store "default"
Added job "my_cron_job2" to job store "default"
Added job "my_interval_job" to job store "default"
Scheduler started
Adding job tentatively -- it will be properly scheduled when the scheduler starts
Adding job tentatively -- it will be properly scheduled when the scheduler starts
Looking for jobs to run
Next wakeup is due at 2015-03-24 15:05:00-07:00 (in 254.210542 seconds)
How can the next wakeup be due 254 seconds from now when the interval job is set to 5 seconds??
You need to keep the thread alive. Here is a example of how I used it.
from subprocess import call
import time
import os
from pytz import utc
from apscheduler.schedulers.background import BackgroundScheduler
def job():
print("In job")
call(['python', 'scheduler/main.py'])
if __name__ == '__main__':
scheduler = BackgroundScheduler()
scheduler.configure(timezone=utc)
scheduler.add_job(job, 'interval', seconds=10)
scheduler.start()
print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
try:
# This is here to simulate application activity (which keeps the main thread alive).
while True:
time.sleep(5)
except (KeyboardInterrupt, SystemExit):
# Not strictly necessary if daemonic mode is enabled but should be done if possible
scheduler.shutdown()
I haven't figured out what caused the original issue, but I got around it by swapping the order in which the jobs are scheduled, so that the 'interval' job is scheduled BEFORE the 'cron' jobs.
i.e. I switched from this:
def my_cron_job1():
print "cron job 1"
def my_cron_job2():
print "cron job 2"
def my_interval_job():
print "interval job"
if __name__ == '__main__':
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler(timezone='MST')
sched.add_job(my_cron_job1, 'cron', id='my_cron_job1', minute=10)
sched.add_job(my_cron_job2, 'cron', id='my_cron_job2', minute=20)
sched.add_job(my_interval_job, 'interval', id='my_job_id', seconds=5)
to this:
def my_cron_job1():
print "cron job 1"
def my_cron_job2():
print "cron job 2"
def my_interval_job():
print "interval job"
if __name__ == '__main__':
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler(timezone='MST')
sched.add_job(my_interval_job, 'interval', id='my_job_id', seconds=5)
sched.add_job(my_cron_job1, 'cron', id='my_cron_job1', minute=10)
sched.add_job(my_cron_job2, 'cron', id='my_cron_job2', minute=20)
and now both the cron jobs and the interval jobs run without a problem in both environments.
How can the next wakeup be due 254 seconds from now when the interval
job is set to 5 seconds??
It's simple:
you have many pending executions as your most of the jobs didn't completed in the interval-window of time.
You could use the following parameters in order to sort this out:
**misfire_grace_time**: Maximum time in seconds for the job execution to be allowed to delay before it is considered a misfire
**coalesce**: Roll several pending executions of jobs into one
To read more, check the documentation here.
The documentation had an error there. I've fixed it now.
That first line should be:
from apscheduler.schedulers.blocking import BlockingScheduler
It would've raised an ImportError though, but you didn't mention any.
Did you try any of the provided examples?
Ok, I've looked at the updated question.
The reason you're having problems may be that you could be using the wrong timezone. Your country is currently using daylight saving time in most locations, so the correct timezone would probably be MDT (Mountain Daylight Time). But that will break again when you move back to standard time. So I advise you to use a timezone like "America/Denver". That will take care of the DST switches.
Question: Are you using CentOS? So far it's the only known operating system where automatic detection of the local timezone is impossible.

Categories