This is an automated email from the ASF dual-hosted git repository. kaxilnaik pushed a commit to branch v3-0-test in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 3eeb2533a425dd25ffeebd5e71306f048a12f38c Author: Kaxil Naik <[email protected]> AuthorDate: Fri Apr 25 22:55:15 2025 +0530 Fix execution API server URL handling for relative paths (#49782) Follow-up of https://github.com/apache/airflow/pull/49747 which broke some workflows including `breeze start-airflow`, requiring https://github.com/apache/airflow/pull/49753. When base_url is a relative path (starts with '/'), default to using http://localhost:8080 as the base URL. This maintains backward compatibility with the previous default behavior while still allowing custom absolute URLs through either `base_url` or `execution_api_server_url` configuration. Fixes `httpx.UnsupportedProtocol` error (as seen in https://github.com/apache/airflow/pull/49753) that occurred when base_url was a relative path without protocol. (cherry picked from commit 3b9ae489a56cde7fe1cd663d7da88fabb831c664) --- airflow-core/src/airflow/config_templates/config.yml | 3 ++- airflow-core/src/airflow/executors/local_executor.py | 3 +++ airflow-core/tests/unit/executors/test_local_executor.py | 11 ++++++++++- .../providers/celery/executors/celery_executor_utils.py | 3 +++ .../edge3/src/airflow/providers/edge3/cli/edge_command.py | 3 +++ 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/airflow-core/src/airflow/config_templates/config.yml b/airflow-core/src/airflow/config_templates/config.yml index f63e39180e7..f6824e3da38 100644 --- a/airflow-core/src/airflow/config_templates/config.yml +++ b/airflow-core/src/airflow/config_templates/config.yml @@ -537,7 +537,8 @@ core: execution_api_server_url: description: | The url of the execution api server. Default is ``{BASE_URL}/execution/`` - where ``{BASE_URL}`` is the base url of the API Server. + where ``{BASE_URL}`` is the base url of the API Server. If ``{BASE_URL}`` is not set, + it will use ``http://localhost:8080`` as the default base url. version_added: 3.0.0 type: string example: ~ diff --git a/airflow-core/src/airflow/executors/local_executor.py b/airflow-core/src/airflow/executors/local_executor.py index 867c1bc254e..4c8ca1e73cb 100644 --- a/airflow-core/src/airflow/executors/local_executor.py +++ b/airflow-core/src/airflow/executors/local_executor.py @@ -110,6 +110,9 @@ def _execute_work(log: logging.Logger, workload: workloads.ExecuteTask) -> None: setproctitle(f"airflow worker -- LocalExecutor: {workload.ti.id}") base_url = conf.get("api", "base_url", fallback="/") + # If it's a relative URL, use localhost:8080 as the default + if base_url.startswith("/"): + base_url = f"http://localhost:8080{base_url}" default_execution_api_server = f"{base_url.rstrip('/')}/execution/" # This will return the exit code of the task process, but we don't care about that, just if the diff --git a/airflow-core/tests/unit/executors/test_local_executor.py b/airflow-core/tests/unit/executors/test_local_executor.py index c693d5a6f76..eb4b9528d1c 100644 --- a/airflow-core/tests/unit/executors/test_local_executor.py +++ b/airflow-core/tests/unit/executors/test_local_executor.py @@ -185,8 +185,17 @@ class TestLocalExecutor: }, "http://custom-server/execution/", ), + ({}, "http://localhost:8080/execution/"), + ({("api", "base_url"): "/"}, "http://localhost:8080/execution/"), + ({("api", "base_url"): "/airflow/"}, "http://localhost:8080/airflow/execution/"), + ], + ids=[ + "base_url_fallback", + "custom_server", + "no_base_url_no_custom", + "base_url_no_custom", + "relative_base_url", ], - ids=["base_url_fallback", "custom_server"], ) @mock.patch("airflow.sdk.execution_time.supervisor.supervise") def test_execution_api_server_url_config(self, mock_supervise, conf_values, expected_server): diff --git a/providers/celery/src/airflow/providers/celery/executors/celery_executor_utils.py b/providers/celery/src/airflow/providers/celery/executors/celery_executor_utils.py index 7956e6d90e7..002c20145d9 100644 --- a/providers/celery/src/airflow/providers/celery/executors/celery_executor_utils.py +++ b/providers/celery/src/airflow/providers/celery/executors/celery_executor_utils.py @@ -159,6 +159,9 @@ def execute_workload(input: str) -> None: log.info("[%s] Executing workload in Celery: %s", celery_task_id, workload) base_url = conf.get("api", "base_url", fallback="/") + # If it's a relative URL, use localhost:8080 as the default + if base_url.startswith("/"): + base_url = f"http://localhost:8080{base_url}" default_execution_api_server = f"{base_url.rstrip('/')}/execution/" supervise( diff --git a/providers/edge3/src/airflow/providers/edge3/cli/edge_command.py b/providers/edge3/src/airflow/providers/edge3/cli/edge_command.py index 19dba52deea..40f8a430132 100644 --- a/providers/edge3/src/airflow/providers/edge3/cli/edge_command.py +++ b/providers/edge3/src/airflow/providers/edge3/cli/edge_command.py @@ -272,6 +272,9 @@ class _EdgeWorkerCli: try: base_url = conf.get("api", "base_url", fallback="/") + # If it's a relative URL, use localhost:8080 as the default + if base_url.startswith("/"): + base_url = f"http://localhost:8080{base_url}" default_execution_api_server = f"{base_url.rstrip('/')}/execution/" supervise(
