()
| 1483 | |
| 1484 | |
| 1485 | def identify_orphaned_workflows(): |
| 1486 | orphaned = [] |
| 1487 | |
| 1488 | # Identify expiry datetime. |
| 1489 | gc_max_idle = cfg.CONF.workflow_engine.gc_max_idle_sec |
| 1490 | utc_now_dt = date_utils.get_datetime_utc_now() |
| 1491 | expiry_dt = utc_now_dt - datetime.timedelta(seconds=gc_max_idle) |
| 1492 | |
| 1493 | # Identify action executions that are still running. The action execution start timestamp |
| 1494 | # does not necessary means it is the max idle time. The use of workflow_executions_idled_ttl |
| 1495 | # to filter is to reduce the number of action executions that need to be evaluated. |
| 1496 | query_filters = { |
| 1497 | "runner__name": "orquesta", |
| 1498 | "status": ac_const.LIVEACTION_STATUS_RUNNING, |
| 1499 | "start_timestamp__lte": expiry_dt, |
| 1500 | } |
| 1501 | ac_ex_dbs = ex_db_access.ActionExecution.query(**query_filters) |
| 1502 | |
| 1503 | for ac_ex_db in ac_ex_dbs: |
| 1504 | # Figure out the runtime for the action execution. |
| 1505 | status_change_logs = sorted( |
| 1506 | [ |
| 1507 | log |
| 1508 | for log in ac_ex_db.log |
| 1509 | if log["status"] == ac_const.LIVEACTION_STATUS_RUNNING |
| 1510 | ], |
| 1511 | key=lambda x: x["timestamp"], |
| 1512 | reverse=True, |
| 1513 | ) |
| 1514 | |
| 1515 | if len(status_change_logs) <= 0: |
| 1516 | continue |
| 1517 | |
| 1518 | runtime = (utc_now_dt - status_change_logs[0]["timestamp"]).total_seconds() |
| 1519 | |
| 1520 | # Fetch the task executions for the workflow execution. |
| 1521 | # Ensure that the root action execution is not being selected. |
| 1522 | wf_ex_id = ac_ex_db.context["workflow_execution"] |
| 1523 | wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_id) |
| 1524 | query_filters = {"workflow_execution": wf_ex_id, "id__ne": ac_ex_db.id} |
| 1525 | tk_ac_ex_dbs = ex_db_access.ActionExecution.query(**query_filters) |
| 1526 | |
| 1527 | # The workflow execution is orphaned if there are |
| 1528 | # no task executions and runtime passed expiry. |
| 1529 | if len(tk_ac_ex_dbs) <= 0 and runtime > gc_max_idle: |
| 1530 | msg = "The action execution is orphaned and will be canceled by the garbage collector." |
| 1531 | update_progress(wf_ex_db, msg) |
| 1532 | orphaned.append(ac_ex_db) |
| 1533 | continue |
| 1534 | |
| 1535 | # The workflow execution is orphaned if there are no active task execution and |
| 1536 | # the end_timestamp of the most recent task execution passed expiry. |
| 1537 | has_active_tasks = len([t for t in tk_ac_ex_dbs if t.end_timestamp is None]) > 0 |
| 1538 | |
| 1539 | completed_tasks = [ |
| 1540 | t |
| 1541 | for t in tk_ac_ex_dbs |
| 1542 | if t.end_timestamp is not None and t.end_timestamp <= expiry_dt |
nothing calls this directly
no test coverage detected