Skip to content

perf: await the framework health check directly when there are no probes - #349

Merged
lesnik512 merged 1 commit into
mainfrom
health-skip-gather-without-probes
Oct 28, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
health-skip-gather-without-probes

Conversation

@lesnik512

@lesnik512 lesnik512 commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Fixes #337.

HealthChecksInstrument.define_health_status always ran asyncio.gather over the framework check and every probe in health_checks_probes. With no probes, the default, that wrapped a single coroutine in a Task and cost two event-loop iterations per health request.

With no probes, it now returns await self._define_framework_health_status() directly. With probes configured it still uses gather, so they keep running concurrently; test_healthchecks_probes_run_concurrently covers that path. FastStream's _define_framework_health_status still pings its brokers through its own gather; I left it alone, since a broker list is the case gather exists for.

Test, written first and failing on main:

  • test_healthchecks_status_without_probes_skips_gather: with asyncio.gather wrapped in a MagicMock that still calls through, define_health_status() returns True and the mock is never called. On main it was called once.

Measured with benchmarks/frameworks on macOS (Apple M2, CPython 3.14), in-process, per health request. Both columns use the same venv with only this file swapped, over 3 interleaved runs of 3 repeats:

scenario main this branch
Litestar health, over a plain handler with the same JSON body (health_ping) +46 to +49 µs +0.3 to +1.4 µs
FastAPI health, over bare +58 to +59 µs +4.8 to +5.2 µs

#337 measured +7.1 to +0.4 µs (Litestar) and +22.6 to +9.3 µs (FastAPI) on Linux. The saving is larger on a Mac because each event-loop iteration costs more there (KqueueSelector.select(0) against EpollSelector), as the issue noted. The Linux numbers are the ones to expect in production.

Checked locally: lint and ty are clean, all 400 tests pass on the branch rebased onto #348, and coverage is 100%.

Not breaking.

With no health_checks_probes, the default, asyncio.gather wrapped the one framework check in a Task and cost two event-loop iterations per health request.

Fixes #337.
@lesnik512
lesnik512 merged commit 9b045e6 into main Oct 28, 2026
35 checks passed
@lesnik512
lesnik512 deleted the health-skip-gather-without-probes branch October 28, 2026 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Skip asyncio.gather in the health check when there are no probes

1 participant