Add support for cron expressions for scheduling timer functions

This commit is contained in:
Peter Stockings
2025-11-27 15:51:15 +11:00
parent f3c2664b31
commit 3f9fa79515
7 changed files with 152 additions and 44 deletions

View File

@@ -8,6 +8,7 @@ if os.environ.get('FLASK_ENV') != 'production':
import asyncio
import aiohttp
import json
from datetime import datetime, timezone, timedelta
from flask import Flask
from extensions import db, init_app
from flask_apscheduler import APScheduler
@@ -54,17 +55,26 @@ async def execute_timer_function_async(timer_function):
response_data = await response.json()
# Update environment and record invocation
# Calculate next run time based on trigger type
next_run = None
if timer_function.get('trigger_type') == 'interval' and timer_function.get('frequency_minutes'):
next_run = datetime.now(timezone.utc) + timedelta(minutes=timer_function['frequency_minutes'])
elif timer_function.get('trigger_type') == 'cron' and timer_function.get('cron_expression'):
from croniter import croniter
try:
next_run = croniter(timer_function['cron_expression'], datetime.now(timezone.utc)).get_next(datetime)
except Exception as e:
print(f"Error calculating next cron run for timer {timer_function['id']}: {str(e)}")
next_run = None
# For 'date' trigger type, next_run should be NULL (one-time execution)
db.execute("""
UPDATE timer_functions
SET environment = %s::jsonb,
last_run = NOW(),
next_run = CASE
WHEN trigger_type = 'interval'
THEN NOW() + (frequency_minutes || ' minutes')::interval
ELSE NULL
END
next_run = %s
WHERE id = %s
""", [json.dumps(response_data['environment']), timer_function['id']], commit=True)
""", [json.dumps(response_data['environment']), next_run, timer_function['id']], commit=True)
# Record the invocation
db.execute("""
@@ -105,7 +115,7 @@ def check_and_execute_timer_functions():
timer_functions = db.execute("""
SELECT
id, name, code, environment, version_number,
trigger_type, frequency_minutes, run_date,
trigger_type, frequency_minutes, run_date, cron_expression,
next_run, enabled, runtime,
EXTRACT(EPOCH FROM (NOW() - next_run)) as seconds_since_next_run
FROM timer_functions