Skip to content

0.6.0 — Resilience observability

Choose a tag to compare

@lesnik512 lesnik512 released this 05 Jun 18:47
7cf653b

httpware 0.6.0 — Resilience observability

0.6.0 is additive. No breaking changes. Code written against 0.5.0 continues to work unchanged.

This release adds operational-event emission to Retry and Bulkhead via two channels — stdlib logging records (always on) and OpenTelemetry span events (opt-in via the otel extra). Re-introduces the otel extra (PR #24 removed it as YAGNI; this release brings it back paired with the code that uses it).

New features

  • Structured logging on resilience operations. Acquire logging.getLogger("httpware.retry") and logging.getLogger("httpware.bulkhead") to see four operational events:
    • retry.giving_up (WARNING) — max_attempts exhausted; attributes include attempts, method, url, last_status, last_exception_type
    • retry.budget_refused (WARNING) — RetryBudget refused to permit a retry
    • retry.streaming_refused (WARNING) — streaming-body marker prevented an otherwise-retryable retry
    • bulkhead.rejected (WARNING) — acquire_timeout elapsed without acquisition; attributes include max_concurrent, acquire_timeout, method, url
  • Optional OpenTelemetry attribute enrichment. Install httpware[otel] (which pulls opentelemetry-api>=1.20, just the API — you supply the SDK). When installed, the same four events are added to the active span via trace.get_current_span().add_event(name, attributes=...). We never create our own spans — for HTTP-level tracing install opentelemetry-instrumentation-httpx separately.

Backwards compatibility

Purely additive:

  • All previously-shipping methods behave identically.
  • Successful retries and successful bulkhead acquisitions emit nothing — the four events fire only on operational concern.
  • Per engineering.md §2, httpware never configures handlers, levels, or calls logging.basicConfig(). Consumers own their logging configuration.
  • The otel extra is opt-in — pip install httpware continues to work without opentelemetry-api.

Usage

import logging
from httpware import AsyncClient, Bulkhead, Retry

# Enable visibility into retry / bulkhead operational events
logging.getLogger("httpware.retry").setLevel(logging.WARNING)
logging.getLogger("httpware.bulkhead").setLevel(logging.WARNING)

# Your normal application logging config picks up the records
logging.basicConfig(level=logging.WARNING, format="%(asctime)s %(name)s %(message)s")

async with AsyncClient(
    base_url="https://api.example.com",
    middleware=[Bulkhead(max_concurrent=10), Retry()],
) as client:
    await client.get("/users/1")
    # On a 503 + retry exhaustion you'll see:
    # 2026-06-05 12:00:00 httpware.retry retry gave up after 3 attempts

For OTel span events:

pip install httpware[otel]
# Plus your SDK + opentelemetry-instrumentation-httpx for HTTP-level spans

What's still ahead

Epic 5's original 5-1 (hook protocol) and 5-4 (standalone OTel middleware) stories are retired, not deferred. Rationale in the spec: opentelemetry-instrumentation-httpx already covers transport-level tracing, and a hook system without a built-in consumer is infrastructure for code that doesn't exist. The structured-emission contract we're shipping is already extensible — users plug into standard logging handlers without needing httpware-specific hooks.

This effectively closes Epic 5. Remaining roadmap is Epic 6 (ship v1.0): docs site (mkdocs), benchmarks, Trusted Publishers + Sigstore release flow.

References