Add support for cron expressions for scheduling timer functions
This commit is contained in:
@@ -17,10 +17,11 @@ CREATE TABLE timer_functions (
|
||||
user_id INT NOT NULL, -- the referencing column
|
||||
|
||||
trigger_type VARCHAR(20) NOT NULL CHECK (
|
||||
trigger_type IN ('interval', 'date')
|
||||
trigger_type IN ('interval', 'date', 'cron')
|
||||
),
|
||||
frequency_minutes INT, -- used if trigger_type = 'interval'
|
||||
run_date TIMESTAMPTZ, -- used if trigger_type = 'date' (one-off)
|
||||
cron_expression TEXT, -- used if trigger_type = 'cron'
|
||||
|
||||
next_run TIMESTAMPTZ,
|
||||
last_run TIMESTAMPTZ,
|
||||
@@ -154,7 +155,7 @@ def overview():
|
||||
timer_functions = db.execute("""
|
||||
SELECT id, name, code, environment, trigger_type,
|
||||
frequency_minutes, run_date, next_run,
|
||||
last_run, enabled, invocation_count, runtime
|
||||
last_run, enabled, invocation_count, runtime, cron_expression
|
||||
FROM timer_functions
|
||||
WHERE user_id = %s
|
||||
ORDER BY id DESC
|
||||
@@ -185,7 +186,7 @@ def new():
|
||||
runtime = data.get('runtime', 'node')
|
||||
|
||||
# Validate trigger type
|
||||
if trigger_type not in ('interval', 'date'):
|
||||
if trigger_type not in ('interval', 'date', 'cron'):
|
||||
return jsonify({
|
||||
"status": "error",
|
||||
"message": "Invalid trigger type"
|
||||
@@ -193,19 +194,41 @@ def new():
|
||||
|
||||
# Calculate next_run based on trigger type
|
||||
next_run = None
|
||||
frequency_minutes = None
|
||||
run_date = None
|
||||
cron_expression = None
|
||||
|
||||
if trigger_type == 'interval':
|
||||
frequency_minutes = int(data.get('frequency_minutes'))
|
||||
next_run = datetime.now(timezone.utc) + timedelta(minutes=frequency_minutes)
|
||||
elif trigger_type == 'date':
|
||||
run_date = datetime.fromisoformat(data.get('run_date'))
|
||||
next_run = run_date
|
||||
elif trigger_type == 'cron':
|
||||
from croniter import croniter
|
||||
cron_expression = data.get('cron_expression')
|
||||
|
||||
# Validate cron expression
|
||||
try:
|
||||
if not croniter.is_valid(cron_expression):
|
||||
return jsonify({
|
||||
"status": "error",
|
||||
"message": "Invalid cron expression format"
|
||||
}), 400
|
||||
# Calculate first run time
|
||||
next_run = croniter(cron_expression, datetime.now(timezone.utc)).get_next(datetime)
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
"status": "error",
|
||||
"message": f"Invalid cron expression: {str(e)}"
|
||||
}), 400
|
||||
|
||||
# Insert new timer function
|
||||
db.execute("""
|
||||
INSERT INTO timer_functions
|
||||
(name, code, environment, user_id, trigger_type,
|
||||
frequency_minutes, run_date, next_run, enabled, runtime)
|
||||
VALUES (%s, %s, %s::jsonb, %s, %s, %s, %s, %s, %s, %s)
|
||||
frequency_minutes, run_date, cron_expression, next_run, enabled, runtime)
|
||||
VALUES (%s, %s, %s::jsonb, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING id
|
||||
""", [
|
||||
data.get('name'),
|
||||
@@ -213,8 +236,9 @@ def new():
|
||||
data.get('environment_info'),
|
||||
current_user.id,
|
||||
trigger_type,
|
||||
frequency_minutes if trigger_type == 'interval' else None,
|
||||
run_date if trigger_type == 'date' else None,
|
||||
frequency_minutes,
|
||||
run_date,
|
||||
cron_expression,
|
||||
next_run,
|
||||
True,
|
||||
runtime
|
||||
@@ -239,8 +263,8 @@ def edit(function_id):
|
||||
# Fetch the timer function
|
||||
timer_function = db.execute("""
|
||||
SELECT id, name, code, environment, version_number, trigger_type,
|
||||
frequency_minutes, run_date, next_run,
|
||||
last_run, enabled, invocation_count, runtime
|
||||
frequency_minutes, run_date, cron_expression, next_run,
|
||||
last_run, enabled, invocation_count, runtime
|
||||
FROM timer_functions
|
||||
WHERE id = %s AND user_id = %s
|
||||
""", [function_id, current_user.id], one=True)
|
||||
@@ -271,7 +295,7 @@ def edit(function_id):
|
||||
runtime = data.get('runtime', 'node')
|
||||
|
||||
# Validate trigger type
|
||||
if trigger_type not in ('interval', 'date'):
|
||||
if trigger_type not in ('interval', 'date', 'cron'):
|
||||
return jsonify({
|
||||
"status": "error",
|
||||
"message": "Invalid trigger type"
|
||||
@@ -279,12 +303,34 @@ def edit(function_id):
|
||||
|
||||
# Calculate next_run based on trigger type
|
||||
next_run = None
|
||||
frequency_minutes = None
|
||||
run_date = None
|
||||
cron_expression = None
|
||||
|
||||
if trigger_type == 'interval':
|
||||
frequency_minutes = int(data.get('frequency_minutes'))
|
||||
next_run = datetime.now(timezone.utc) + timedelta(minutes=frequency_minutes)
|
||||
elif trigger_type == 'date':
|
||||
run_date = datetime.fromisoformat(data.get('run_date'))
|
||||
next_run = run_date
|
||||
elif trigger_type == 'cron':
|
||||
from croniter import croniter
|
||||
cron_expression = data.get('cron_expression')
|
||||
|
||||
# Validate cron expression
|
||||
try:
|
||||
if not croniter.is_valid(cron_expression):
|
||||
return jsonify({
|
||||
"status": "error",
|
||||
"message": "Invalid cron expression format"
|
||||
}), 400
|
||||
# Calculate first run time
|
||||
next_run = croniter(cron_expression, datetime.now(timezone.utc)).get_next(datetime)
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
"status": "error",
|
||||
"message": f"Invalid cron expression: {str(e)}"
|
||||
}), 400
|
||||
|
||||
# Update timer function
|
||||
db.execute("""
|
||||
@@ -295,6 +341,7 @@ def edit(function_id):
|
||||
trigger_type = %s,
|
||||
frequency_minutes = %s,
|
||||
run_date = %s,
|
||||
cron_expression = %s,
|
||||
next_run = %s,
|
||||
enabled = %s,
|
||||
runtime = %s
|
||||
@@ -305,8 +352,9 @@ def edit(function_id):
|
||||
data.get('script_content'),
|
||||
data.get('environment_info'),
|
||||
trigger_type,
|
||||
frequency_minutes if trigger_type == 'interval' else None,
|
||||
run_date if trigger_type == 'date' else None,
|
||||
frequency_minutes,
|
||||
run_date,
|
||||
cron_expression,
|
||||
next_run,
|
||||
data.get('is_enabled', True), # Default to True if not provided
|
||||
runtime,
|
||||
@@ -371,12 +419,12 @@ def toggle(function_id):
|
||||
"status": "error",
|
||||
"message": "Timer function not found or unauthorized"
|
||||
}), 404
|
||||
|
||||
|
||||
# Fetch updated timer functions for the overview template
|
||||
timer_functions = db.execute("""
|
||||
SELECT id, name, code, environment, trigger_type,
|
||||
frequency_minutes, run_date, next_run,
|
||||
last_run, enabled, invocation_count, runtime
|
||||
last_run, enabled, invocation_count, runtime, cron_expression
|
||||
FROM timer_functions
|
||||
WHERE user_id = %s
|
||||
ORDER BY id DESC
|
||||
|
||||
Reference in New Issue
Block a user