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(

Reply via email to