Luke Gregorio
08/22/2025, 7:33 AMMarvin
08/22/2025, 7:33 AMMarvin
08/22/2025, 7:37 AMprefect flow-run cancel <FLOW_RUN_ID>
Force the state to Cancelled (API/Client)
- This bypasses the worker and flips Prefect’s record to Cancelled. It will not kill the underlying job; you’ll need to stop it in your infra (Kubernetes job/pod, ECS task, Docker container, local process).
Async client:
from prefect.client.orchestration import get_client
from prefect.states import Cancelled
import asyncio
async def force_cancel(flow_run_id: str):
async with get_client() as client:
await client.set_flow_run_state(flow_run_id, state=Cancelled(), force=True)
asyncio.run(force_cancel("<FLOW_RUN_ID>"))
Sync client:
from prefect.client.orchestration import SyncPrefectClient
from prefect.states import Cancelled
with SyncPrefectClient() as client:
client.set_flow_run_state("<FLOW_RUN_ID>", state=Cancelled(), force=True)
API reference: Set flow run state API
Notes
- “Cancelling” for hours usually means the worker never acknowledged the cancel (worker offline/crashed) or the infrastructure job is stuck. After forcing the state above, make sure to terminate the actual job in your environment.
- If you just want to remove the record after forcing the state, you can delete it:
prefect flow-run delete <FLOW_RUN_ID>
If you need help stopping the underlying job, let me know your worker/infrastructure (Kubernetes, ECS, Docker, local) and I can share the exact steps. Also, do you use Prefect Cloud or self-hosted UI?Luke Gregorio
08/22/2025, 7:39 AMLuke Gregorio
08/22/2025, 7:39 AMMarvin
08/22/2025, 7:39 AMMarvin
08/22/2025, 7:40 AMprefect flow-run cancel <FLOW_RUN_ID>
2) Force the state via API/Client (bypasses the worker)
- This flips Prefect’s record to Cancelled. It will not kill the underlying job — you’ll need to stop it on your infra (K8s/ECS/Docker/etc.).
Python client:
from prefect.client.orchestration import SyncPrefectClient
from prefect.states import Cancelled
with SyncPrefectClient() as client:
client.set_flow_run_state("<FLOW_RUN_ID>", state=Cancelled(), force=True)
cURL (direct REST call to your server):
curl -X POST \
"<YOUR_PREFECT_API_URL>/flow_runs/<FLOW_RUN_ID>/set_state" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_TOKEN_IF_CONFIGURED>" \
-d '{
"state": {
"type": "CANCELLED",
"name": "Cancelled",
"message": "Force cancel via API"
},
"force": true
}'
API reference: Set flow run state API
After forcing the state, be sure to terminate the actual workload:
- Kubernetes: kubectl delete job <job>
or kubectl delete pod <pod>
- Docker: docker stop <container>
(then docker rm
)
- ECS: stop the task in the service/cluster
- Process/local: kill the PID on the worker host
If you tell me which work pool/infrastructure you’re using (Kubernetes, Docker, ECS, Process, etc.), I can provide exact commands to safely stop the underlying job.Luke Gregorio
08/22/2025, 7:41 AMMarvin
08/22/2025, 7:41 AMMarvin
08/22/2025, 7:43 AMfrom prefect.client.orchestration import SyncPrefectClient
from prefect.states import Cancelled
with SyncPrefectClient() as client:
client.set_flow_run_state("<FLOW_RUN_ID>", state=Cancelled(), force=True)
Or via REST:
curl -X POST \
"<YOUR_PREFECT_API_URL>/flow_runs/<FLOW_RUN_ID>/set_state" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_TOKEN_IF_CONFIGURED>" \
-d '{
"state": {"type": "CANCELLED", "name": "Cancelled", "message": "Force cancel via API"},
"force": true
}'
API ref: Set flow run state API
Step 2 — Delete the Kubernetes Job/Pod for that run
- Prefect labels k8s resources with the flow run ID; commonly: <http://prefect.io/flow-run-id=<FLOW_RUN_ID|prefect.io/flow-run-id=<FLOW_RUN_ID>>
. If you customized the job template, adjust the selector accordingly.
Find the resources:
FLOW_RUN_ID=<FLOW_RUN_ID>
kubectl get job,pod -A -l <http://prefect.io/flow-run-id=$FLOW_RUN_ID|prefect.io/flow-run-id=$FLOW_RUN_ID> -o wide
Delete the Job (preferred; it will cascade to Pods):
kubectl delete job -n <NAMESPACE> -l <http://prefect.io/flow-run-id=$FLOW_RUN_ID|prefect.io/flow-run-id=$FLOW_RUN_ID> --cascade=foreground
If there’s only a Pod (or it’s stuck), force delete the Pod:
kubectl delete pod -n <NAMESPACE> -l <http://prefect.io/flow-run-id=$FLOW_RUN_ID|prefect.io/flow-run-id=$FLOW_RUN_ID> --force --grace-period=0
Notes
- Do Step 1 first so the worker doesn’t recreate the Job.
- If you’re unsure of the namespace, use -A
to locate it, then run the delete in that namespace.
- If finalizers or termination hang, the --force --grace-period=0
on the Pod command will hard-kill it.
Kubernetes worker docs (config, templates, labels): Kubernetes deployment and workers
If you paste the flow run ID here, I can give you the exact kubectl commands with your namespace.