Skip to content

Conversation

@jason810496
Copy link
Member

@jason810496 jason810496 commented Jun 30, 2025

closes: #52526
related: https://lists.apache.org/thread/hfr8q85rgr6knpp5wblbz301ysnmzhht

Why

  • Move Flask ( or FAB you said ) out of airflow-core dependency

What

Replace Flask's send_from_directory fastapi_app.mount with JWTAuthStaticFiles ( which inherent from FastAPI's StaticFiles and extend the existed authorization. reference from fastapi/fastapi#858 (comment) )

@jason810496 jason810496 self-assigned this Jun 30, 2025
@jason810496 jason810496 added the full tests needed We need to run full set of tests for this PR to merge label Jun 30, 2025
@jason810496 jason810496 force-pushed the refactor/logging/replace-flask-serve-log-with-fastapi branch from 8be599f to 99651ed Compare June 30, 2025 18:00
@jason810496 jason810496 force-pushed the refactor/logging/replace-flask-serve-log-with-fastapi branch from 99651ed to b5facdf Compare June 30, 2025 18:02
@jason810496 jason810496 marked this pull request as ready for review June 30, 2025 18:02
Copy link
Member Author

@jason810496 jason810496 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I though there isn't Flask'ssend_from_directory alternative in FastAPI.
So I implement the validation for file path in first try ( and the security check is angry ).

Fortunately I found the gist for having authorization for FastAPI's StaticFiles. ( linked in the PR description )

@potiuk
Copy link
Member

potiuk commented Jul 1, 2025

One other thing - I think we can get rid of those dependencies from airflow-core/pyproject.toml:

   # We could get rid of flask and gunicorn if we replace serve_logs with a starlette + unicorn
    "flask>=2.1.1",
    # We could get rid of flask and gunicorn if we replace serve_logs with a starlette + unicorn
    "gunicorn>=20.1.0",

@jason810496
Copy link
Member Author

Thanks @potiuk @pierrejeambrun for the review! I will resolve the comments tomorow.

@jason810496 jason810496 marked this pull request as draft July 2, 2025 16:17
@potiuk
Copy link
Member

potiuk commented Jul 2, 2025

Thanks @potiuk @pierrejeambrun for the review! I will resolve the comments tomorow.

Cool!

@jason810496 jason810496 marked this pull request as ready for review July 3, 2025 15:58
@jason810496
Copy link
Member Author

One other thing - I think we can get rid of those dependencies from airflow-core/pyproject.toml:

   # We could get rid of flask and gunicorn if we replace serve_logs with a starlette + unicorn
    "flask>=2.1.1",
    # We could get rid of flask and gunicorn if we replace serve_logs with a starlette + unicorn
    "gunicorn>=20.1.0",

Just found out that we can't remove gunicorn that we are still using gunicorn for Daemonized the API server if user pass --daemon flag.

else:
if args.daemon:
daemonize()
log.info("Daemonized the API server process PID: %s", os.getpid())

I can raise another PR to add the daemonize util as a new airflow.util and remove the gunicorn package before merging this one.

@jason810496 jason810496 marked this pull request as draft July 3, 2025 16:27
@jason810496 jason810496 force-pushed the refactor/logging/replace-flask-serve-log-with-fastapi branch from f09810c to 85df9a7 Compare July 8, 2025 10:28
@potiuk
Copy link
Member

potiuk commented Jul 8, 2025

👀 :)

Fix test_invalid_characters_handled

Refactor with StaticFiles
@potiuk potiuk merged commit d8a3ad2 into apache:main Jul 9, 2025
104 checks passed
@pierrejeambrun
Copy link
Member

Super cool!

HsiuChuanHsu pushed a commit to HsiuChuanHsu/airflow that referenced this pull request Jul 10, 2025
* Refactor serve_logs with FastAPI

Fix test_invalid_characters_handled

Refactor with StaticFiles

* Remove details for 403 forbidden response

* Replace Gunicorn with Uvicorn

* Fix uvicorn multiple workers error

* Remove flask and gunicorn from airflow-core/pyproject.toml

* Remove old serve_logs module and add gunicorn to spelling_wordlist
stephen-bracken pushed a commit to stephen-bracken/airflow that referenced this pull request Jul 15, 2025
* Refactor serve_logs with FastAPI

Fix test_invalid_characters_handled

Refactor with StaticFiles

* Remove details for 403 forbidden response

* Replace Gunicorn with Uvicorn

* Fix uvicorn multiple workers error

* Remove flask and gunicorn from airflow-core/pyproject.toml

* Remove old serve_logs module and add gunicorn to spelling_wordlist
kaxil added a commit to astronomer/airflow that referenced this pull request Sep 9, 2025
The `airflow scheduler` fails to start with this error when the logs directory doesn't exist:

```
RuntimeError: Directory '/root/airflow/logs' does not exist
```

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

**Module Import Order Dependency**: FastAPI's `StaticFiles` validates directory existence at app creation time, but this happens at **module import time** before Airflow's initialization sequence:

```python
uvicorn.run("airflow.utils.serve_logs.log_server:app")  # imports module
↓
app = create_app()  # runs immediately at module level
↓
StaticFiles(directory=log_directory)  # FAILS: directory doesn't exist yet
```

**Expected initialization order**:
```
settings.initialize() → configure_logging() → init_log_folder() → create_app()
```

**Actual order with eager loading**:
```
import log_server → create_app() → FAIL (directory doesn't exist)
```

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```

This implementation follows the same pattern as Airflow's main API:

| Component | Pattern | File |
|-----------|---------|------|
| **Main API** | `cached_app()` with global caching | `api_fastapi/app.py` |
| **serve_logs** | `get_app()` with global caching | `utils/serve_logs/log_server.py` |

Both use lazy initialization with global app caching, ensuring proper startup order while maintaining performance.

---

**Fixes**: Scheduler startup failures with LocalExecutor
**Related-to**: d8a3ad2
kaxil added a commit to astronomer/airflow that referenced this pull request Sep 9, 2025
Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
kaxil added a commit that referenced this pull request Sep 9, 2025
Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [#52581](#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
kaxil added a commit to astronomer/airflow that referenced this pull request Sep 9, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
Brunda10 pushed a commit to Brunda10/airflow that referenced this pull request Sep 17, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Sep 30, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 1, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 2, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 3, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 4, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 5, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 5, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 7, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 8, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 9, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 10, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 11, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 12, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 14, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 15, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 17, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
abdulrahman305 bot pushed a commit to abdulrahman305/airflow that referenced this pull request Oct 19, 2025
…e#55443)

Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [apache#52581](apache#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```
kosteev pushed a commit to GoogleCloudPlatform/composer-airflow that referenced this pull request Oct 24, 2025
Remove workers parameter from `uvicorn.run()` in `serve_logs` to fix file
descriptor errors when scheduler starts serve_logs as a subprocess.
The original implementation used `workers=2` (copied from Gunicorn) but
this caused multiprocessing issues in containerized environments.

Also implemented lazy app loading via `get_app()` function for better
initialization order and architectural consistency with main API.

The primary fix addresses: OSError: [Errno 9] Bad file descriptor. Secondary improvement ensures proper initialization timing.

This regression was introduced in [#52581](apache/airflow#52581) when serve_logs was refactored from Flask to FastAPI.

---
Without this fix, we see following error when running `airflow standalone` fresh in an isolated container:

Error 1:

```
scheduler  | Traceback (most recent call last):
scheduler  | File "/.venv/bin/airflow", line 10, in <module>
scheduler  | sys.exit(main())
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/__main__.py", line 55, in main
scheduler  | args.func(args)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/cli_config.py", line 49, in command
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/cli.py", line 114, in wrapper
scheduler  | return f(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/providers_configuration_loader.py", line 54, in wrapped_function
scheduler  | return func(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 52, in scheduler
scheduler  | run_command_with_daemon_option(
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/daemon_utils.py", line 86, in run_command_with_daemon_option
scheduler  | callback()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 55, in <lambda>
scheduler  | callback=lambda: _run_scheduler_job(args),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 42, in _run_scheduler_job
scheduler  | with _serve_logs(args.skip_serve_logs), _serve_health_check(enable_health_check):
scheduler  | File "/usr/local/lib/python3.10/contextlib.py", line 135, in __enter__
scheduler  | return next(self.gen)
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/cli/commands/scheduler_command.py", line 62, in _serve_logs
scheduler  | from airflow.utils.serve_logs import serve_logs
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/__init__.py", line 20, in <module>
scheduler  | from airflow.utils.serve_logs.log_server import create_app
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 160, in <module>
scheduler  | app = create_app()
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 153, in create_app
scheduler  | JWTAuthStaticFiles(directory=log_directory, html=False),
scheduler  | File "/.venv/lib/python3.10/site-packages/airflow/utils/serve_logs/log_server.py", line 49, in __init__
scheduler  | super().__init__(*args, **kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/starlette/staticfiles.py", line 56, in __init__
scheduler  | raise RuntimeError(f"Directory '{directory}' does not exist")
scheduler  | RuntimeError: Directory '/root/airflow/logs' does not exist
```

Error 2:

This was because we had harcoded 2 workers! but this isn't needed
```
scheduler  | Process SpawnProcess-1:53:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
scheduler  | Process SpawnProcess-1:54:
scheduler  | Traceback (most recent call last):
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
scheduler  | self.run()
scheduler  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
scheduler  | self._target(*self._args, **self._kwargs)
scheduler  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
scheduler  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
scheduler  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
scheduler  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
scheduler  | OSError: [Errno 9] Bad file descriptor
triggerer  | Process SpawnProcess-1:53:
triggerer  | Traceback (most recent call last):
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
triggerer  | self.run()
triggerer  | File "/usr/local/lib/python3.10/multiprocessing/process.py", line 108, in run
triggerer  | self._target(*self._args, **self._kwargs)
triggerer  | File "/.venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 73, in subprocess_started
triggerer  | sys.stdin = os.fdopen(stdin_fileno)  # pragma: full coverage
triggerer  | File "/usr/local/lib/python3.10/os.py", line 1030, in fdopen
triggerer  | return io.open(fd, mode, buffering, encoding, *args, **kwargs)
triggerer  | OSError: [Errno 9] Bad file descriptor
```

GitOrigin-RevId: 1d9e6c0fc96bb6b507481b4d721c7f0c350d6981
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:logging full tests needed We need to run full set of tests for this PR to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Convert serve_logs to use fast-api

4 participants