Skip to content

fix: two silently-inert capabilities found by building a service on 26.07.01 (release 26.09.01) - #160

Merged
ancongui merged 1 commit into
mainfrom
fix/dworkers-findings
Sep 10, 2026
Merged

fix: two silently-inert capabilities found by building a service on 26.07.01 (release 26.09.01)#160
ancongui merged 1 commit into
mainfrom
fix/dworkers-findings

Conversation

@ancongui

Copy link
Copy Markdown
Contributor

Two defects found while building a production service (dworkers) against 26.07.01. Both are the same
shape: a capability PyFly advertises, wired in a way that silently did nothing.

Fixed

The OTLP endpoint is now built to the OpenTelemetry specification.
OTEL_EXPORTER_OTLP_ENDPOINT is a base url — the SDK appends the per-signal path — while
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT and the exporter's own endpoint= argument are the complete url,
used verbatim. TracingAutoConfiguration read the base variable and handed it straight to
OTLPSpanExporter(endpoint=...), collapsing the two: an operator who set the spec-correct
http://collector:4318 got an exporter POSTing to http://collector:4318, which is not a signal endpoint,
so every span was dropped and nothing was logged. The only way to make it work was to write a value into
the base variable that the spec says is not a base.

Both spellings work now — a url with no path is treated as a base and gains /v1/traces, one that already
has a path is left alone — and the same normalisation applies to pyfly.observability.tracing.otlp.endpoint.

@sse_mapping routes appear in the OpenAPI document.
collect_route_metadata() looked only at __pyfly_mapping__, so server-sent-event routes were absent from
/openapi.json and from pyfly openapi with nothing said about it. A CI job that exports the document and
diffs it — the standard way to keep an HTTP surface honest — could not see the streaming half of the API at
all, and a deleted stream read as no change. SSE is plain HTTP, so it is now emitted as the GET it is, with a
text/event-stream success response.

Added

x-pyfly-websocket-routes. WebSocket has no OpenAPI representation — that is what AsyncAPI is for — but
leaving @websocket_mapping routes out entirely made the document quietly incomplete in the same way SSE
was. ControllerRegistrar.collect_websocket_routes() reports them and the generator publishes them under
this document-level extension: still not operations, but visible, diffable, and honest about what the
document does not cover. Wired through pyfly openapi, the Starlette adapter and the FastAPI adapter alike.

opentelemetry-exporter-otlp-proto-http as a dev dependency. OTLP is the exporter
TracingAutoConfiguration selects by default as soon as an endpoint is configured, yet it appears in no
extra — so no CI job ever imported it and the entire OTLP path, the endpoint bug above included, went
unexercised. Dev-only: applications still choose and pay for their own exporter.

Changed

The README version badge, which the v26.07.01 release left at 26.06.114.

Verification

Gate Result
pytest tests/ (CI's ignore set) 4998 passed, 7 skipped, 0 failed
mypy src/pyfly --strict no issues in 694 source files
ruff check / ruff format --check passed / 1274 files formatted
uv build sdist + wheel built

Version bumped to 26.09.01 (PEP 440 26.9.1) with a CHANGELOG entry. The tag is deliberately not
pushed — pushing v* publishes, and that is a human decision.

…6.07.01

- observability: TracingAutoConfiguration read OTEL_EXPORTER_OTLP_ENDPOINT — a
  BASE url per the OTel spec — and passed it to OTLPSpanExporter(endpoint=...),
  which wants the COMPLETE signal url. An operator setting the spec-correct
  http://collector:4318 got an exporter POSTing to a non-signal path, so every
  span was dropped with nothing logged. Both spellings now work, from either the
  env var or pyfly.observability.tracing.otlp.endpoint.

- web: collect_route_metadata() looked only at __pyfly_mapping__, so @sse_mapping
  routes never reached /openapi.json or `pyfly openapi`. SSE is plain HTTP and is
  now emitted as the GET it is, with a text/event-stream response. WebSocket has
  no OpenAPI representation, so @websocket_mapping routes are published under the
  new document-level x-pyfly-websocket-routes extension rather than omitted in
  silence — a deleted stream used to read as no change in an OpenAPI diff.

- dev: opentelemetry-exporter-otlp-proto-http joins the dev group. OTLP is the
  default exporter yet appeared in no extra, so CI never imported it and the whole
  OTLP path, endpoint bug included, went unexercised.

Also corrects the README version badge, left at 26.06.114 by the v26.07.01 release.

Release 26.09.01.
@ancongui
ancongui merged commit c52938a into main Sep 10, 2026
6 checks passed
@ancongui
ancongui deleted the fix/dworkers-findings branch September 10, 2026 02:16
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.

1 participant