OpenTelemetry trace propagation & email bounce/complaint suppression contract#965
Open
aabxtract wants to merge 2 commits into
Open
OpenTelemetry trace propagation & email bounce/complaint suppression contract#965aabxtract wants to merge 2 commits into
aabxtract wants to merge 2 commits into
Conversation
Add suppression state machine to bounceStore with hard bounce, soft bounce cap, and complaint tracking. Tests prove: hard bounce suppresses immediately, soft bounces retry up to configurable cap then suppress, complaints suppress regardless of bounce history, and isSuppressed/getSuppressionInfo provide queryable short-circuit for the notification pipeline.
|
@aabxtract Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Description
feat+test: OpenTelemetry trace propagation & email bounce/complaint suppression contract
Summary
This PR delivers two independently scoped changes that were developed in parallel on feature/otel-tracing and
test/email-bounce-suppression:
Wires W3C-compliant distributed tracing across the full HTTP → job → blockchain pipeline so a single create_vault
request can be followed from the inbound Express handler through Soroban submission, ETL job execution, and webhook
delivery as one connected trace.
New files:
no-op fallback, TracerImpl with batched flushing and head-based sampling
span per request, injects outgoing traceparent header, attaches trace context + correlation ID to req
success/error paths, no-op tracer, initTracing options, middleware traceparent propagation, correlation-ID fallback
chain, and job queue span instrumentation
Instrumented call sites:
soroban.tx_hash, and RPC failover events
and HTTP status
Bootstrap integration:
OTEL_TRACES_SAMPLER_ARG
Env contract (no-op when unset):
┌─────────────────────────────┬────────────────────────────────────────────────────────────────────────┐
│ Variable │ Purpose │
├─────────────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ OTEL_EXPORTER_OTLP_ENDPOINT │ Collector URL (e.g. http://jaeger:4318). Tracing disabled when absent. │
├─────────────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ OTEL_SERVICE_NAME │ Service name tag on spans. Defaults to disciplr-backend. │
├─────────────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ OTEL_TRACES_SAMPLER │ always_on / always_off / traceidratio. Defaults to always_on. │
├─────────────────────────────┼────────────────────────────────────────────────────────────────────────┤
│ OTEL_TRACES_SAMPLER_ARG │ Sampling ratio 0.0–1.0 when sampler is traceidratio. │
└─────────────────────────────┴────────────────────────────────────────────────────────────────────────┘
Proves the suppression rules enforced by bounceStore.ts so the notification pipeline never re-mails a poisoned
address. All three suppression paths are covered and isolated.
Changed files:
getSuppressionInfo (typed SuppressionReason), getSoftBounceCount, setSoftBounceCap, getBounces, getComplaints, and
clearBounces
Suppression rules proven by the tests:
┌───────────────────────────────────────┬───────────────────────────────────────────────────────────────────────┐
│ Event │ Outcome │
├───────────────────────────────────────┼───────────────────────────────────────────────────────────────────────┤
│ Hard bounce (or SMTP 550/554/5.1.1) │ Immediate suppression; reason: "hard_bounce" │
├───────────────────────────────────────┼───────────────────────────────────────────────────────────────────────┤
│ Soft bounce × N < cap │ Not suppressed; count tracked │
├───────────────────────────────────────┼───────────────────────────────────────────────────────────────────────┤
│ Soft bounce × N ≥ cap │ Suppressed; reason: "soft_bounce_cap" │
├───────────────────────────────────────┼───────────────────────────────────────────────────────────────────────┤
│ Spam complaint │ Immediate suppression; reason: "complaint" — overrides bounce history │
├───────────────────────────────────────┼───────────────────────────────────────────────────────────────────────┤
│ isSuppressed() / getSuppressionInfo() │ Short-circuit query for the notification pipeline │
└───────────────────────────────────────┴───────────────────────────────────────────────────────────────────────┘
Precedence order: complaint > hard bounce > soft-bounce cap
Test plan
unaffected
Jaeger/Grafana Alloy instance
closes #678
closes #654