0

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.

1
  • Can you try with the pytz library to handles time zone and daylight saving adjustments automatically? Commented Nov 14, 2024 at 6:55

2 Answers 2

1

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

Use @app.schedule decorator. the schedule parameter must be in a literal string. This means that dynamic inputs, such as variables or functions, cannot be used directly for the schedule.

The Azure Functions runtime requires a static schedule to properly configure the timer. This can be the cause for the above issue.

Here is the modified existing function app code with the @app.schedule decorator.

import datetime  
import logging  
import pytz  # Make sure to install pytz if you haven't already  

import azure.functions as func  

app = func.FunctionApp()  

def is_dst(date):  
    """Check if the given date is in Daylight Saving Time."""  
    tz = pytz.timezone("America/Chicago")  # Change to your desired timezone  
    # Ensure the date is naive before localizing  
    naive_date = date.replace(tzinfo=None)  # Remove tzinfo to make it naive  
    localized_date = tz.localize(naive_date)  
    return bool(localized_date.dst().seconds)  

@app.schedule(  
    schedule="0 */1 * * * *",  # Change this to your desired CRON schedule  
    arg_name="myTimer",  
    run_on_startup=False,  
    use_monitor=True  
)  
def timer_trigger(myTimer: func.TimerRequest) -> None:  
    # Get the current time in the specified timezone  
    tz = pytz.timezone("America/Chicago")  # Change to your desired timezone  
    current_time = datetime.datetime.now(tz)  
    utc_timestamp = datetime.datetime.utcnow().replace(  
        tzinfo=datetime.timezone.utc).isoformat()  

    if myTimer.past_due:  
        logging.info('The timer is past due!')  

    logging.info('Python timer trigger function ran at %s', utc_timestamp)  

    # Check if it's currently DST  
    if is_dst(current_time):  
        logging.info('Current time is in Daylight Saving Time.')  
        # Add your logic for DST here  
    else:  
        logging.info('Current time is in Standard Time.')  
        # Add your logic for Standard Time here  

    # Log the current local time  
    logging.info('Current local time is %s', current_time.isoformat())
  • Check that the pytz library is installed in your Azure Function environment.

enter image description here

Deployment status:

enter image description here

Succeeded:

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much for writing this thorough answer and for confirming that Azure only accepts literal strings. Is there a way to tell the function app to wait an hour if it isn't DST? Also, would this increase costs to have the app on, but not doing anything, for an hour for the first invocation of each day? I forgot to mention I am using the consumption plan.
0

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.

  • Use a function to determine if your condition is met
## 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.

  • Schedule the function to fire at two different times, based on summer/winter time.In the function itself you perform the check:
@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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.