Python schedule a function to run every 10 seconds using Sched - python

I want to have a function run every 10 seconds. The script is scheduled on Airflow to run between 9 am to 11 am.
If the condition is met, the process schedule will stop. However, it seems the function only ran once. Can anyone help let me know what I should modify to make it work?
'''
import pandas as pd
import sched, time
import datetime
import smtplib
import io
'''
'''
def timedTask():
scheduler = sched.scheduler(time.time, time.sleep)
scheduler.enter(10, 1, task)
scheduler.run()
'''
'''
def task():
dq_value = % sql
if dq_value > 1:
return
else:
print("wait")
'''
'''
timedTask()
'''

Related

Run a function at a random time in Python

I want to be able to be able to run a function at a random time as long as the program is running.
Let's say I have this function:
def sample_func:
print("Function is running.")
and some other code running. As long as the program is being run, I want this function to run at a random amount of time between 5 to 10 minutes while other code is being run. Is this possible?
Here's the code you're looking. Set the sleep timer for 5-10 minutes.
Insert your main flow code inside the "main flow" function.
import random
import threading
import time
def random_function():
print("Function is running.")
def call_random_function():
while True:
time.sleep(random.randint(1, 5))
random_function()
def main_flow():
"""
Do your main flow here
"""
a = 1
while a < 10:
print(a)
a += 1
time.sleep(10)
if __name__ == '__main__':
threading.Thread(target=call_random_function).start()
main_flow()
print("Program is finished.")

Import update in Python

So I want to import * from a phyton file. However, these variables I want to import are connected to an API. So they change.
For instance:
at 3:35 is A=5
at 3:36 is A=6
So I want my import to be done every 15 second. How do I write this?
Just use it this way where I just show the schedule to show how the variables can be changed in two files and the schedule represented the change of the API.
In the file1.py
import schedule
import time
def job(t):
var1=5
print(var1)
schedule.every().day.at("3:35").do(job,'It is 3:35')
while True:
schedule.run_pending()
time.sleep(15) # wait one minute
In the file2.py
from file1 import var1
import schedule
import time
def job(t):
var1=6
print(var1)
schedule.every().day.at("3:36").do(job,'It is 3:36')
while True:
schedule.run_pending()
time.sleep(15) # wait one minute

Python schedule "Time is freezing"

I am using schedule to do functions that work with the real-time datetime.datetime.now().
But when calling the function datetime.datetime.now() i always get start time schedule script.
Example:
import schedule
import time
import datetime
schedule.every(2).minutes.do(print, datetime.datetime.now().strftime("%d-%m-%Y %H:%M"))
while 1:
schedule.run_pending()
time.sleep(1)
Example result:
28-04-2021 19:59
28-04-2021 19:59
28-04-2021 19:59
28-04-2021 19:59
Does anyone have any ideas how one can get real time during the execution of the scheduler?
Python => 3.8
schedule => 1.1.0
This is because the return value of now() gets saved in memory. Pass a lambda or function to ensure it is dynamically calculated:
import schedule
import time
import datetime
schedule.every(2).minutes.do(
lambda: print(datetime.datetime.now().strftime("%d-%m-%Y %H:%M"))
)
while 1:
schedule.run_pending()
time.sleep(1)
This is because value of now is already loaded into memory.
Try this
import schedule
import time
import datetime
schedule.every(2).minutes.do(print, datetime.datetime.now().strftime("%d-%m-%Y %H:%M"))
while 1:
schedule.run_pending()
time.sleep(1)

How to access return value from apscheduler?

I can't quite piece together how to access the return values from scheduled jobs in apscheduler. The job needs to run at a different time each day, and I need the return value from today's job to schedule tomorrow's job.
This link (how to get return value from apscheduler jobs) appears to be the best previous answer to this question. It suggests adding a listener to the scheduler. I've added a listener, but I'm not sure how to access it's return value. I can access the listeners attached to the scheduler, but I can't access their outputs. A listener, job_runs() in the code below, will print when a scheduled job runs.
Further, I know I need to access a JobExecutionEvent (https://apscheduler.readthedocs.io/en/latest/modules/events.html#module-apscheduler.events) which holds the return value from the function.
First, the function I want to access is run_all() where a bunch of operations are performed, but I just return True for the test case.
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR, JobExecutionEvent
from datetime import datetime, timedelta
import logging
def run_all():
return True
def job_runs(event): # listener function
if event.exception:
print('The job did not run')
else:
print('The job completed # {}'.format(datetime.now()))
def job_return_val(event): # listener function
return event.retval
Then, I setup the scheduler, add the listeners, and add the job. The trigger is set to run the function 1 minute after the job is added to scheduler.
scheduler = BackgroundScheduler()
scheduler.add_listener(job_runs, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
scheduler.add_listener(job_return_val, EVENT_JOB_EXECUTED)
cron_args = datetime_to_dict(datetime.now() + timedelta(minutes=1))
job = scheduler.add_job(run_all, "cron", **cron_args)
Next, I start the scheduler and print the scheduled job. Additionally, I setup logging so I know where the scheduler is.
test = scheduler.start()
scheduler.print_jobs()
logging.basicConfig()
logging.getLogger('apscheduler').setLevel(logging.DEBUG)
With the logging enabled, the scheduler reports that the job is run and removed from the scheduler, as I expect it to. job_runs() prints the correct output to the console. And with breakpoints, I know job_return_val() is called. However, I have no clue where the value it returns is sent to. The function appears to be called in a different thread called APScheduler. I don't know much about threads, but that makes sense. However, I do not understand when the output from that thread is returned to the main thread.
Finally, I've tried instantiating a JobExceptionEvent with the code, job_id, jobstore, and scheduled_run_time accessible from the attributes of scheduler and job, but the JobExceptionEvent does not seem to have any knowledge that the event was run in scheduler. That also seems to make sense due to the threading described in the preceding paragraph.
Any help in sorting through this would be great!
The return value of listener is not used anywhere (see the code), so there's no use to return any value anyway. If you need to schedule another job based on the value of previous job (acquired in the listener via the event object), you have to do it right in that listener.
EDIT: To illustrate how to do it (and prove it's possible), see this sample code:
from datetime import datetime
import time
from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_EXECUTED
from apscheduler.schedulers.background import BackgroundScheduler
def tick():
print('Tick! The time is: %s' % datetime.now())
def tack():
print('Tack! The time is: %s' % datetime.now())
def listener(event):
if not event.exception:
job = scheduler.get_job(event.job_id)
if job.name == 'tick':
scheduler.add_job(tack)
if __name__ == '__main__':
scheduler = BackgroundScheduler()
scheduler.add_listener(listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
scheduler.add_job(tick, 'interval', seconds=5)
scheduler.start()
try:
while True:
time.sleep(1)
except (KeyboardInterrupt, SystemExit):
scheduler.shutdown()
The output:
(venv) pasmen#nyx:~/tmp/x$ python test.py
Tick! The time is: 2019-04-03 19:51:29.192420
Tack! The time is: 2019-04-03 19:51:29.195878
Tick! The time is: 2019-04-03 19:51:34.193145
Tack! The time is: 2019-04-03 19:51:34.194898
Tick! The time is: 2019-04-03 19:51:39.193207
Tack! The time is: 2019-04-03 19:51:39.194868
Tick! The time is: 2019-04-03 19:51:44.193223
Tack! The time is: 2019-04-03 19:51:44.195066
...
You can use global variables for now. Here's an example:
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
def fn():
'''Increase `times` by one and print it.'''
global times
times += 1
print(times)
sched = BlockingScheduler()
times = 0
# Execute fn() each second.
sched.add_job(fn, trigger=CronTrigger(second='*/1'))
sched.start()
What you need would require the stateful jobs feature to be implemented.
I encountered the same problem a few days ago. My first solution was using keyword global, but not long before I realized it was problematic, because the variables defined outside the job could unexpectedly be changed, especially when they are local variables in a loop.
Then I thought about using listeners, too. But the callback passed into a listener takes only the event as a single argument, which means the only information you can get from the callback is the event itself, profoundly limiting what you could possibly do.
Finally I choose to pass a func to the task to be scheduled, which works fine to me. What you really have to do is just to use the return value of the scheduled task as an argument for the func, as the code below shows.
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
scheduler = BlockingScheduler()
def job_with_return(a:int, b:int, callback_return):
# You can do something heavier here with the inputs.
result = a + b
print(f'[in job] result is {result}')
if callback_return:
callback_return(result)
scheduler.add_job(func=job_with_return,
trigger='date',
args=(1, 2, lambda r: print(f'[out of job]: result is {r}')),
run_date=datetime.now(),
)
scheduler.start()
The output:
[in job] result is 3
[out of job]: result is 3
As to the request of OP,
The job needs to run at a different time each day, and I need the
return value from today's job to schedule tomorrow's job.
you can additionally feed the func with the scheduler as well as the time you want the task to run in tomorrow, so that you can arrange a schedule in the func.
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime, timedelta
scheduler = BlockingScheduler()
today = datetime.now()
tomorrow = today + timedelta(seconds=1)
def task_today(a:int, b:int, scheduler:BlockingScheduler, callback_return, tomorrow:datetime):
# What we have to do today is to get the result and use it to schedule tomorrow's task.
result_today = a + b
print(f"[{datetime.now().strftime('%H:%M:%S')}] (Today) The result is {result_today}.")
scheduler.add_job(callback_return, 'date',
args=(result_today,),
run_date=tomorrow,
id='job_tomorrow')
def task_tomorrow(result_from_today:int):
result_tomrrow = result_from_today * 2
print(f"[{datetime.now().strftime('%H:%M:%S')}] (Tommorow) The result is {result_tomrrow}.")
scheduler.add_job(func=task_today,
trigger='date',
args=(1, 2, scheduler, task_tomorrow, tomorrow),
run_date=today,
id='job_today')
scheduler.start()
The output:
[22:22:40] (Today) The result is 3.
[22:22:41] (Tommorow) The result is 6.
You can even make a daily task with a recursion.
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime, timedelta
scheduler = BlockingScheduler()
today = datetime.now()
def task_daily(result_yesterday:int, day_counter:int, scheduler:BlockingScheduler, callback_return):
# You can do something heavier here with more inputs.
result_today = result_yesterday + 2
day_counter += 1
tomorrow = datetime.now() + timedelta(seconds=1)
print(f"[{datetime.now().strftime('%H:%M:%S')}] (day {day_counter}) The result for today is {result_today}.")
scheduler.add_job(task_daily, 'date',
args=(result_today, day_counter, scheduler, callback_return),
run_date=tomorrow)
scheduler.add_job(func=task_daily,
trigger='date',
args=(0, 0, scheduler, task_daily),
run_date=today)
scheduler.start()
The output:
[22:43:17] (day 1) The result for today is 2.
[22:43:18] (day 2) The result for today is 4.
[22:43:19] (day 3) The result for today is 6.
[22:43:20] (day 4) The result for today is 8.
[22:43:21] (day 5) The result for today is 10.
[22:43:22] (day 6) The result for today is 12.
[22:43:23] (day 7) The result for today is 14.

Verifying that an APScheduler task has properly executed

I'm trying to use the APScheduler library to execute a job at two certain times: 1am PST and 2am PST.
Sort of lost, I am trying to figure out what am doing wrong. Here is my code so far:
#!/usr/bin/python
import sys
import re
import urllib
import csv
import urllib2
import logging
import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
logging.basicConfig()
def main():
#Make a rest call, store the output in a csv, close the file.
...
f.close()
sched.add_job(my_job, 'date', run_date = '2015-12-15 01:00:00', args=['text'])
try:
sched.start()
print(datetime.datetime.now())
except (KeyboardInterrupt):
logger.debug('Terminating...')
print (datetime.datetime.now())
The current time is 12:16 PST, I just ran the above script and it executed and created the file prior to the job time of 12:30:30pm; this is for testing purposes.
So, I'm trying to figure out what I am doing wrong with regards to using APScheduler.
I want to improve this code, what are some things I can change?
If you want to run your code at certain times every time, you should be using the cron trigger:
sched.add_job(my_job, 'cron', hour='1,2', args=['text'])
For better debugging:
logging.basicConfig(level=logging.DEBUG)

Categories