Summary
Rather than building one-off wrappers per integration (Sentry, PostHog, etc.), design a lightweight pluggable system that can dispatch to 0..n backends at runtime.
Motivation
Issues #24 (Sentry) and #25 (PostHog) both follow the same pattern: thin wrapper, env var toggle, fire-and-forget. As more integrations are added (Datadog, OpenTelemetry, custom webhooks, etc.), maintaining individual modules per service doesn't scale. A simple adapter pattern avoids this.
Constraints
- 0..n backends — zero active is the default, multiple can run simultaneously
- Runtime-configured — env vars, application config, or both
- Fire-and-forget — reporting must never block or crash conversion
- No shared state required between backends — each is independent
- Burrito-compatible — all adapters compiled in, toggled at runtime
Sketch
defmodule DocSpec.Reporting do
@moduledoc "Dispatches events to all enabled reporting backends."
@type event :: :conversion_started | :conversion_completed | :conversion_failed | :error
@type payload :: map()
@callback handle_event(event(), payload()) :: :ok
@spec report(event(), payload()) :: :ok
def report(event, payload \\ %{}) do
for backend <- enabled_backends() do
Task.start(fn -> backend.handle_event(event, payload) end)
end
:ok
end
defp enabled_backends do
Application.get_env(:docspec, :reporting_backends, [])
end
end
# Adapters implement the callback
defmodule DocSpec.Reporting.Sentry do
@behaviour DocSpec.Reporting
# ...
end
defmodule DocSpec.Reporting.PostHog do
@behaviour DocSpec.Reporting
# ...
end
Configuration:
# runtime.exs or env-var-driven setup
config :docspec, :reporting_backends, [
DocSpec.Reporting.Sentry,
DocSpec.Reporting.PostHog
]
What this replaces
This supersedes the individual wrapper approach described in #24 and #25. Those issues remain valid for the actual Sentry/PostHog adapter implementations — this issue covers the shared dispatch layer they plug into.
Related
Summary
Rather than building one-off wrappers per integration (Sentry, PostHog, etc.), design a lightweight pluggable system that can dispatch to 0..n backends at runtime.
Motivation
Issues #24 (Sentry) and #25 (PostHog) both follow the same pattern: thin wrapper, env var toggle, fire-and-forget. As more integrations are added (Datadog, OpenTelemetry, custom webhooks, etc.), maintaining individual modules per service doesn't scale. A simple adapter pattern avoids this.
Constraints
Sketch
Configuration:
What this replaces
This supersedes the individual wrapper approach described in #24 and #25. Those issues remain valid for the actual Sentry/PostHog adapter implementations — this issue covers the shared dispatch layer they plug into.
Related