Skip to content

fix: eliminate MySQL readiness race in mysql-influxdb e2e - #61

Merged
latte-gh merged 2 commits into
mainfrom
fix/e2e-mysql-readiness
Jul 28, 2026
Merged

fix: eliminate MySQL readiness race in mysql-influxdb e2e#61
latte-gh merged 2 commits into
mainfrom
fix/e2e-mysql-readiness

Conversation

@liuhaoyang

Copy link
Copy Markdown
Member

Problem

The Tier-1 full-stack mysql-influxdb e2e leg fails on CI (flaky; sometimes passed). Root cause: on CI, MySQL first-initializes from an empty data dir and listens only on its unix socket (~12s) before binding TCP 3306. The distributor eagerly connects to MySQL during host startup (ServerVersion.AutoDetect via the StorageExporter hosted service), throws, and restart: always crash-loops it. run-e2e.sh's wait_for_port gets a false-positive from docker-proxy (host port bound immediately), so the OTLP sender fires into the crash-looping distributor and gets Connection refused. The litedb leg has no external DB, so it never races; Tier-2 (Testcontainers) also passes — confirming the storage adapters are fine and the issue is full-stack compose readiness.

Fix

  • docker/docker-compose-mysql-influxdb.yml: add healthchecks for mysql (mysqladmin ping -h 127.0.0.1 — forces TCP so it only passes once the real server binds 3306, not the socket-only first-init server) and influxdb (curl /health), and change distributor/query to depends_on: { condition: service_healthy }. App containers (and thus docker-proxy binding :4317/:5775) no longer start until the databases truly accept connections.
  • e2e/Mocha.E2E.Abstractions/OtlpSender.cs: bounded 30s retry on the initial OTLP export for gRPC Unavailable/DeadlineExceeded (defense-in-depth for the startup window).

No src/ production code changed.

Verification

Locally (real docker stack, mysql-influxdb): databases reach healthy before app containers start; all 4 containers RestartCount=0; distributor log clean (no Unable to connect to any of the specified MySQL hosts, no Restarting); e2e 2/2 case(s) passed. This PR's CI run should show the E2E mysql-influxdb leg green.

The Tier-1 mysql-influxdb e2e was flaky/failing due to a MySQL TCP-readiness
race. On CI, MySQL always first-initializes from empty (the data volume is
commented out and e2e teardown runs `down -v`), so for ~12s it listens only on
its unix socket, not TCP 3306. The distributor eagerly opens a MySQL connection
during host startup (ServerVersion.AutoDetect via AddHostedService<StorageExporter>),
throws "Unable to connect to any of the specified MySQL hosts", exits, and
`restart: always` crash-loops it. run-e2e.sh's wait_for_port then gets a false
positive because docker-proxy binds the published port immediately, so the sender
fires into the crash-looping distributor and hits Connection refused.

Add healthchecks to mysql and influxdb and switch distributor/query to
`depends_on: { condition: service_healthy }`. The MySQL healthcheck pings over
`-h 127.0.0.1` to force TCP, so it only passes once the real server binds 3306
(not the socket-only first-init server). This holds distributor/query — and thus
the docker-proxy binding of 4317/5775 — until both backends truly accept
connections, eliminating the race.

Preserves the commented-out data volume, restart policy, ports, env and seed
wiring. Verified locally: `docker compose up -d` blocks until mysql/influxdb are
healthy, all containers stay at RestartCount=0 with no MySQL-connect error, and
both e2e cases pass (2/2).
Defense-in-depth for the e2e mysql-influxdb readiness race, on top of the
compose healthcheck gating. Even once the distributor container is up, its gRPC
endpoint can briefly report Unavailable (connection refused / not yet listening)
while it finishes wiring up storage. Retry the initial trace/metric export on
transient gRPC status (Unavailable / DeadlineExceeded) for a bounded 30s window
before failing the case, so a healthy-but-slow-starting distributor does not flake
the run. Non-transient failures and window exhaustion still surface the original
RpcException.

Scoped to the e2e sender only; no src/ production code changed.
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.24%. Comparing base (4e9f19c) to head (cfb22ee).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #61      +/-   ##
==========================================
- Coverage   71.26%   71.24%   -0.03%     
==========================================
  Files         156      156              
  Lines        4023     4023              
  Branches      528      528              
==========================================
- Hits         2867     2866       -1     
  Misses        991      991              
- Partials      165      166       +1     

see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@latte-gh latte-gh left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM. Two files, both e2e-only: (1) docker-compose-mysql-influxdb.yml adds proper healthchecks with service_healthy conditions for MySQL/InfluxDB, correctly using TCP ping (-h 127.0.0.1) to avoid false-positive readiness during MySQL socket-only init; (2) OtlpSender.cs adds bounded 30s startup retry for Unavailable/DeadlineExceeded as defense-in-depth. No src/ changes, both commits GPG-verified, CI already proves Tier1 mysql-influxdb passes.

@latte-gh
latte-gh merged commit f74cf79 into main Jul 28, 2026
12 checks passed
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.

2 participants