Copilot commented on code in PR #60940:
URL: https://github.com/apache/airflow/pull/60940#discussion_r2737878846


##########
airflow-core/src/airflow/cli/commands/api_server_command.py:
##########
@@ -50,22 +52,163 @@
 # more info here: 
https://github.com/benoitc/gunicorn/issues/1877#issuecomment-1911136399
 
 
-@enable_memray_trace(component=MemrayTraceComponents.api)
-def _run_api_server(args, apps: str, num_workers: int, worker_timeout: int, 
proxy_headers: bool):
-    """Run the API server."""
+def _build_gunicorn_command(
+    host: str,
+    port: int,
+    num_workers: int,
+    worker_timeout: int,
+    ssl_cert: str | None,
+    ssl_key: str | None,
+    log_level: str,
+    access_log_enabled: bool,
+    proxy_headers: bool,
+) -> list[str]:
+    """
+    Build the gunicorn command line arguments.
+
+    Uses uvicorn.workers.UvicornWorker as the worker class to run the ASGI app.
+    """
+    cmd = [
+        "gunicorn",
+        "airflow.api_fastapi.main:app",
+        "--worker-class",
+        "uvicorn.workers.UvicornWorker",
+        "--config",
+        "python:airflow.api_fastapi.gunicorn_config",
+        "--bind",
+        f"{host}:{port}",
+        "--workers",
+        str(num_workers),
+        "--timeout",
+        str(worker_timeout),
+        "--graceful-timeout",
+        str(worker_timeout),
+        "--keep-alive",
+        str(worker_timeout),
+        "--log-level",
+        log_level,
+        # Preload app to share memory across workers via copy-on-write
+        "--preload",
+    ]
+
+    if ssl_cert and ssl_key:
+        cmd.extend(["--certfile", ssl_cert, "--keyfile", ssl_key])
+
+    # Configure access logging - gunicorn doesn't log access by default
+    if access_log_enabled:
+        cmd.extend(["--access-logfile", "-"])  # Log to stdout
+
+    if proxy_headers:
+        cmd.extend(["--forwarded-allow-ips", "*"])
+
+    return cmd
+
+
+def _run_api_server_with_gunicorn(
+    args,
+    apps: str,
+    num_workers: int,
+    worker_timeout: int,
+    proxy_headers: bool,
+) -> None:
+    """
+    Run the API server using gunicorn with uvicorn workers.
+
+    Gunicorn provides proper master/worker process management with:
+    - SIGTTIN to spawn new workers
+    - SIGTTOU to kill oldest worker (FIFO order - correct for rolling restarts)
+    - Memory sharing via preload + fork copy-on-write
+
+    Runs GunicornMonitor in the main thread (like AF2's webserver pattern).
+    """
+    ssl_cert, ssl_key = _get_ssl_cert_and_key_filepaths(args)
+
+    log_level = conf.get("logging", "uvicorn_logging_level", 
fallback="info").lower()
+    access_log_enabled = log_level not in ("error", "critical", "fatal")
+
+    cmd = _build_gunicorn_command(
+        host=args.host,
+        port=args.port,
+        num_workers=num_workers,
+        worker_timeout=worker_timeout,
+        ssl_cert=ssl_cert,
+        ssl_key=ssl_key,
+        log_level=log_level,
+        access_log_enabled=access_log_enabled,
+        proxy_headers=proxy_headers,
+    )
+
     log.info(
         textwrap.dedent(
             f"""\
-            Running the uvicorn with:
+            Running gunicorn with:
             Apps: {apps}
             Workers: {num_workers}
             Host: {args.host}:{args.port}
             Timeout: {worker_timeout}
-            Logfiles: {args.log_file or "-"}
+            Command: {" ".join(cmd)}
             
================================================================="""
         )
     )

Review Comment:
   This log message duplicates the one at lines 266-277. Consider removing this 
duplicate since it's logged again in the main _run_api_server function.



##########
airflow-core/docs/extra-packages-ref.rst:
##########
@@ -126,6 +126,8 @@ other packages that can be used by airflow or some of its 
providers.
 
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
 | graphviz            | ``pip install 'apache-airflow[graphviz]'``          | 
Graphviz renderer for converting Dag to graphical output                   |
 
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| gunicorn            | ``pip install 'apache-airflow[gunicorn]'``          | 
periodic worker recycling of ``uvicorn`` workers on the API-server         |

Review Comment:
   The description is slightly misleading. Gunicorn doesn't recycle 'uvicorn 
workers' - it uses UvicornWorker as the worker class. Consider: 'Gunicorn 
server with rolling worker restarts for the API server' or 'Worker recycling 
support for the API server'.
   ```suggestion
   | gunicorn            | ``pip install 'apache-airflow[gunicorn]'``          
| Gunicorn server with rolling worker restarts for the API server            |
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to