Skip to content

Commit 68f08cf

Browse files
committed
feat: add active workflow cancellation (#990)
1 parent 4f0a15d commit 68f08cf

17 files changed

Lines changed: 1622 additions & 134 deletions

‎application/single_app/background_tasks.py‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
update_group_workflow_runtime_fields,
4848
)
4949
from functions_settings import get_settings, is_group_workflows_enabled_for_group, update_settings
50-
from functions_workflow_runner import run_group_workflow, run_personal_workflow
50+
from functions_workflow_runner import create_workflow_run_id, run_group_workflow, run_personal_workflow
5151

5252

5353
def _get_lock_holder_id():
@@ -514,18 +514,26 @@ def check_due_workflows_once():
514514
pass
515515

516516
started_at = datetime.now(timezone.utc).isoformat()
517+
active_run_id = create_workflow_run_id()
517518
update_personal_workflow_runtime_fields(
518519
user_id,
519520
workflow_id,
520521
{
521522
'status': 'running',
523+
'active_run_id': active_run_id,
524+
'cancellation_requested_at': None,
525+
'cancellation_requested_by': '',
522526
'last_run_started_at': started_at,
523527
'last_run_trigger_source': trigger_source,
524528
'last_run_error': '',
525529
},
526530
)
527531

528-
result = run_personal_workflow(refreshed_workflow, trigger_source=trigger_source)
532+
result = run_personal_workflow(
533+
refreshed_workflow,
534+
trigger_source=trigger_source,
535+
run_id=active_run_id,
536+
)
529537
update_fields = dict(result.get('workflow_updates') or {})
530538
update_fields['status'] = 'idle'
531539
update_fields['next_run_at'] = compute_next_run_at(refreshed_workflow, from_time=datetime.now(timezone.utc))
@@ -590,18 +598,26 @@ def check_due_workflows_once():
590598
pass
591599

592600
started_at = datetime.now(timezone.utc).isoformat()
601+
active_run_id = create_workflow_run_id()
593602
update_group_workflow_runtime_fields(
594603
group_id,
595604
workflow_id,
596605
{
597606
'status': 'running',
607+
'active_run_id': active_run_id,
608+
'cancellation_requested_at': None,
609+
'cancellation_requested_by': '',
598610
'last_run_started_at': started_at,
599611
'last_run_trigger_source': trigger_source,
600612
'last_run_error': '',
601613
},
602614
)
603615

604-
result = run_group_workflow(refreshed_workflow, trigger_source=trigger_source)
616+
result = run_group_workflow(
617+
refreshed_workflow,
618+
trigger_source=trigger_source,
619+
run_id=active_run_id,
620+
)
605621
update_fields = dict(result.get('workflow_updates') or {})
606622
update_fields['status'] = 'idle'
607623
update_fields['next_run_at'] = compute_next_run_at(refreshed_workflow, from_time=datetime.now(timezone.utc))

‎application/single_app/config.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
EXECUTOR_TYPE = 'thread'
9898
EXECUTOR_MAX_WORKERS = 30
9999
SESSION_TYPE = 'filesystem'
100-
VERSION = "0.250.061"
100+
VERSION = "0.250.062"
101101
IS_DEVELOPMENT = is_development_env_enabled()
102102

103103
SESSION_COOKIE_SAMESITE = os.getenv('SESSION_COOKIE_SAMESITE', 'Lax')

‎application/single_app/functions_group_workflows.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ def save_group_workflow(group_id, workflow_data, actor_user_id, user_info=None):
506506
'last_run_response_preview': (existing_workflow or {}).get('last_run_response_preview', ''),
507507
'last_run_trigger_source': (existing_workflow or {}).get('last_run_trigger_source', ''),
508508
'run_count': int((existing_workflow or {}).get('run_count') or 0),
509+
'active_run_id': (existing_workflow or {}).get('active_run_id', ''),
510+
'cancellation_requested_at': (existing_workflow or {}).get('cancellation_requested_at'),
511+
'cancellation_requested_by': (existing_workflow or {}).get('cancellation_requested_by', ''),
509512
}
510513

511514
if trigger_type in {'interval', 'file_sync'} and is_enabled:

‎application/single_app/functions_personal_workflows.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,9 @@ def save_personal_workflow(user_id, workflow_data, actor_user_id=None):
634634
'last_run_response_preview': (existing_workflow or {}).get('last_run_response_preview', ''),
635635
'last_run_trigger_source': (existing_workflow or {}).get('last_run_trigger_source', ''),
636636
'run_count': int((existing_workflow or {}).get('run_count') or 0),
637+
'active_run_id': (existing_workflow or {}).get('active_run_id', ''),
638+
'cancellation_requested_at': (existing_workflow or {}).get('cancellation_requested_at'),
639+
'cancellation_requested_by': (existing_workflow or {}).get('cancellation_requested_by', ''),
637640
}
638641

639642
if trigger_type in {'interval', 'file_sync'} and is_enabled:

‎application/single_app/functions_workflow_activity.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ def _normalize_status(value):
3434
normalized_value = _normalize_text(value).lower()
3535
if normalized_value in {'running', 'pending', 'in_progress', 'in-progress'}:
3636
return 'running'
37-
if normalized_value in {'failed', 'error', 'cancelled', 'canceled'}:
37+
if normalized_value in {'cancelled', 'canceled'}:
38+
return 'cancelled'
39+
if normalized_value in {'failed', 'error'}:
3840
return 'failed'
3941
if normalized_value in {'completed', 'complete', 'succeeded', 'success', 'done'}:
4042
return 'completed'
@@ -346,5 +348,5 @@ def build_workflow_activity_snapshot(run_record=None, workflow=None, conversatio
346348
'run': _serialize_run(run_record),
347349
'activities': activities,
348350
'lane_count': max(1, len(lane_order) or 1),
349-
'live': _normalize_status((run_record or {}).get('status')) == 'running',
351+
'live': _normalize_text((run_record or {}).get('status')).lower() in {'running', 'cancelling'},
350352
}

0 commit comments

Comments
 (0)