LemonCore. RouterBridge
(lemon_core v0.1.0)
View Source
Optional bridge to :lemon_router without compile-time coupling.
Channel adapters and other producers can forward inbound messages and submit
runs without depending on :lemon_router. :lemon_router configures the
bridge at runtime.
submit_run/1 accepts a canonical %LemonCore.RunRequest{}.
Failure contract
Every function here answers rather than raises, because callers are channel adapters and webhook handlers for whom a router problem is not their problem to crash over. Three failure modes, deliberately distinguished:
- Not configured — no module registered for the role. The documented
fallback:
{:error, :unavailable}, or the soft value (false,:none,[]) for the query functions. - Reached and raised — the router ran in the caller's process and threw
an exception. Answered
{:error, exception}, which is more useful than:unavailablebecause the router was available; something else failed. - Configured but not running — the router module exists, but the process
behind it does not answer, so
GenServer.callexits. An exit is not an exception andrescuedoes not catch it: before this was handled, that exit travelled into whatever called the bridge, which for an HTTP handler meant an opaque 500 and, for a mail webhook, a silently dropped message. Now answered{:error, :unavailable}— the same as never having been configured, because from the caller's side it is the same situation: the router did not take this.
Exits are collapsed to :unavailable rather than reported in detail on
purpose. A timeout, a dead process and a mid-call crash differ in cause but
not in consequence — the work was not accepted and the caller's only real
decision is whether to retry. Reporting them separately invites callers to
match on :unavailable alone and silently mishandle the rest, which is
exactly the bug this contract exists to prevent. Callers that want the detail
should log at their own layer, where they know what the failure means.
Throws are not caught: no router throws, and one that did would be a bug worth surfacing rather than flattening into "unavailable".
Summary
Functions
Configure bridge modules with merge/guard modes.
Configure bridge modules with conflict protection.
Types
Functions
Configure bridge modules with merge/guard modes.
Modes:
:replace- replace configured keys directly:merge- merge with existing config, preserving unspecified keys:safe_merge- like merge, but rejects conflicting non-nil overrides
Configure bridge modules with conflict protection.
@spec submit_run(LemonCore.RunRequest.t()) :: {:ok, binary()} | {:error, :unavailable} | {:error, term()}