My server runs on a start and stop schedule that unfortunately follows daylight saving time. I am looking for a way to dynamically change the CRON schedule on my function app to account for daylight saving time. This is easy in the python code; however, the function app timer trigger doesn't work when you set anything other than a literal string to the schedule
parameter of azure.functions.FunctionApp.schedule()
.
import azure.functions as func
import logging
app = func.FunctionApp()
@app.schedule(
schedule="<cron_schedule>"
,arg_name="myTimer"
,run_on_startup=False
,use_monitor=True
)
def timer_trigger(myTimer: func.TimerRequest) -> None:
if myTimer.past_due:
logging.info('The timer is past due!')
logging.info('Python timer trigger function executed.')
For example, in @app.schedule()
, if you set schedule = "0 35 * * * *"
, the scheduler triggers on the 35th minute every hour as expected. After verifying that literal strings work, I tried the following approaches which allow for dynamic inputs:
schedule=f"0 {35} * * * *"
var_cron = "0 35 * * * *"
schedule=var_cron
schedule="0 {minutes} * * * *".format(minutes=35)
Even though the Timer Trigger Issue Analysis application insight in the diagnostic hub shows the CRON as 0 35 * * * *
for all of these approaches, the app does not actually trigger. Manually running the app in the azure portal returns no errors. Also, the diagnostic view "Functions that are not triggering" returns no errors. From every angle I thought to check, it seems Azure understands what is being passed into the schedule
parameter of @app.schedule()
. Is there another python approach you can think of trying? Is this a known bug on Azure's side? Any help is very much appreciated.
not sure if still needed, but here is how I solved it for myself. This example asumes a run at 23:00 Stockholm local time regardless on summer/winter time.
## WILL RUN SCRIPT BASED ON LOCAL TIME ##
def should_run_script():
"""
Run at 23:00
"""
time_now = datetime.datetime.now(pytz.timezone('Europe/Stockholm'))
current_time = time_now.time()
start_time = datetime.time(22, 50, 0)
end_time = datetime.time(23, 10, 0)
in_window = start_time <= current_time < end_time
logging.debug(f"Current Stockholm time: {current_time}, In window: {in_window}")
return in_window
I give it a window of 20 mins insteaf of a fixed time in case the function is fired slightly before or after the scheduled time.
@app.schedule(schedule="0 0 21,22 * * *", arg_name="myTimer", run_on_startup=False,
use_monitor=True)
def timer_trigger(myTimer: func.TimerRequest) -> None:
try:
if myTimer.past_due:
logging.info('The timer is past due!')
# Exit early if conditions are not met
if not should_run_script():
logging.info('Conditions not met; exiting function.')
return
This will run the function twice a day, but based on this condition check it will pass through to the "main" execution only once a day. You only "wasting" a couple of seconds of compute for the "dry" execution when the time condition is now met.
Hope that helps.