This is an automated email from the ASF dual-hosted git repository.
henry3260 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new c4ab0c326d2 Fix airflowctl backfill pause/unpause/cancel always
failing with 405 (#73282)
c4ab0c326d2 is described below
commit c4ab0c326d2223b05c845ae33c2bc196ca642d58
Author: Y-C <[email protected]>
AuthorDate: Fri Sep 18 03:06:08 2026 +0800
Fix airflowctl backfill pause/unpause/cancel always failing with 405
(#73282)
The API server registers these three backfill routes as PUT only, so every
invocation was rejected before reaching the handler. The commands have never
worked since the routes were introduced in the AIP-84 migration, which means
an operator cannot stop a backfill that is consuming the cluster.
The three tests covering them asserted only the request path, so the mock
transport accepted any verb and kept the mismatch green all along.
Co-authored-by: Eason09053360
<[email protected]>
---
airflow-ctl/src/airflowctl/api/operations.py | 6 +++---
airflow-ctl/tests/airflow_ctl/api/test_operations.py | 3 +++
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/airflow-ctl/src/airflowctl/api/operations.py
b/airflow-ctl/src/airflowctl/api/operations.py
index 5a054d79a3c..0b8a0d9670a 100644
--- a/airflow-ctl/src/airflowctl/api/operations.py
+++ b/airflow-ctl/src/airflowctl/api/operations.py
@@ -391,17 +391,17 @@ class BackfillOperations(BaseOperations):
def pause(self, backfill_id: str) -> BackfillResponse |
ServerResponseError:
"""Pause a backfill."""
- self.response = self.client.post(f"backfills/{backfill_id}/pause")
+ self.response = self.client.put(f"backfills/{backfill_id}/pause")
return BackfillResponse.model_validate_json(self.response.content)
def unpause(self, backfill_id: str) -> BackfillResponse |
ServerResponseError:
"""Unpause a backfill."""
- self.response = self.client.post(f"backfills/{backfill_id}/unpause")
+ self.response = self.client.put(f"backfills/{backfill_id}/unpause")
return BackfillResponse.model_validate_json(self.response.content)
def cancel(self, backfill_id: str) -> BackfillResponse |
ServerResponseError:
"""Cancel a backfill."""
- self.response = self.client.post(f"backfills/{backfill_id}/cancel")
+ self.response = self.client.put(f"backfills/{backfill_id}/cancel")
return BackfillResponse.model_validate_json(self.response.content)
diff --git a/airflow-ctl/tests/airflow_ctl/api/test_operations.py
b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
index 5b6a8641905..cdf78859058 100644
--- a/airflow-ctl/tests/airflow_ctl/api/test_operations.py
+++ b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
@@ -680,6 +680,7 @@ class TestBackfillOperations:
def test_pause(self):
def handle_request(request: httpx.Request) -> httpx.Response:
+ assert request.method == "PUT"
assert request.url.path ==
f"/api/v2/backfills/{self.backfill_id}/pause"
return httpx.Response(200,
json=json.loads(self.backfill_response.model_dump_json()))
@@ -689,6 +690,7 @@ class TestBackfillOperations:
def test_unpause(self):
def handle_request(request: httpx.Request) -> httpx.Response:
+ assert request.method == "PUT"
assert request.url.path ==
f"/api/v2/backfills/{self.backfill_id}/unpause"
return httpx.Response(200,
json=json.loads(self.backfill_response.model_dump_json()))
@@ -698,6 +700,7 @@ class TestBackfillOperations:
def test_cancel(self):
def handle_request(request: httpx.Request) -> httpx.Response:
+ assert request.method == "PUT"
assert request.url.path ==
f"/api/v2/backfills/{self.backfill_id}/cancel"
return httpx.Response(200,
json=json.loads(self.backfill_response.model_dump_json()))