macula_response behaviour (macula v10.0.1)
View SourceBehaviour for supervised RPC responses.
advertise/5 on the raw SDK takes a bare handler fun invoked in a transient process spawned per inbound CALL (see the internal macula_station_link advertise/5 — "Handlers run in a transient process spawned per CALL"). This module gives that transient process a proper shape: each inbound call starts one supervised macula_response child (under a simple_one_for_one factory this module owns), threading state through Module:init/1 and Module:handle_request/2, and publishing rpc.received_v1 / rpc.replied_v1 mesh facts around the request. This is the provider-side counterpart to macula_request.
A crashing Module:handle_request/2 kills the response child; that composes with the SDK's own crash mapping unchanged, since gen_server:call/3 against a dead callee raises the same way a crashing bare handler fun already does.
Example
-module(math_service).
-behaviour(macula_response).
-export([init/1, handle_request/2]).
init(_Args) -> {ok, []}.
handle_request(#{a := A, b := B}, State) ->
{reply, #{result => A + B}, State}. {ok, _Sup} = macula_response:advertise(Pool, Realm,
<<"math.add_v1">>, math_service, []).Direct-dial
advertise/5,6 registers the handler with the pool's advertise- gossip mechanism only — nothing published lets a caller on another station find this procedure without a route having propagated between the two stations first. advertise_direct/6 does that AND publishes a signed procedure_advertisement DHT record naming this pool's currently-connected station as the server, so a caller using macula_request:start_link_direct/6,7 can resolve and dial here directly, in one hop, regardless of whether the two stations have a routing edge between them.
Summary
Functions
Advertise Procedure on Pool/Realm. Starts a private factory supervisor for per-request response children and registers a dispatch handler with macula:advertise/5. Returns the supervisor pid so the caller can supervise it (or ignore it).
As advertise/5. Opts may include announce (default true) and auth (forwarded to macula:advertise/5).
As advertise/5, and additionally publishes a signed procedure_advertisement DHT record naming this pool's connected station as the server, so macula_request:start_link_direct/6,7 can resolve and dial here directly. Identity signs the advertisement — reuse the same one across re-advertises so each one doesn't mint a fresh advertiser identity.
As advertise_direct/6, with Opts forwarded BOTH to advertise/6 (so announce/auth apply here too) and to macula_direct_dial:publish_advertisement/5 — e.g. cert_chain => ChainPem (leaf ++ org CA, PEM), so a verifying consumer's verify_cert_chain opt can check this advertiser's org/realm authorization (Slice 7c Direction B, managed realms only. See macula_direct_dial's module doc, "Trust model") — each side reads only the keys it recognizes, so one Opts map serves both.
Stop advertising. Does not stop the factory supervisor returned by advertise/5,6 — callers that want to tear it down should exit(Sup, shutdown) themselves.
Callbacks
Functions
-spec advertise(macula:pool(), macula:realm(), macula:procedure(), module(), term()) -> {ok, pid()} | {error, term()}.
Advertise Procedure on Pool/Realm. Starts a private factory supervisor for per-request response children and registers a dispatch handler with macula:advertise/5. Returns the supervisor pid so the caller can supervise it (or ignore it).
-spec advertise(macula:pool(), macula:realm(), macula:procedure(), module(), term(), map()) -> {ok, pid()} | {error, term()}.
As advertise/5. Opts may include announce (default true) and auth (forwarded to macula:advertise/5).
-spec advertise_direct(macula:pool(), macula:realm(), macula:procedure(), module(), term(), macula_identity:key_pair()) -> {ok, pid()} | {error, term()}.
As advertise/5, and additionally publishes a signed procedure_advertisement DHT record naming this pool's connected station as the server, so macula_request:start_link_direct/6,7 can resolve and dial here directly. Identity signs the advertisement — reuse the same one across re-advertises so each one doesn't mint a fresh advertiser identity.
The DHT publish is best-effort: if it fails (e.g. no healthy link at that instant), the handler is still advertised and reachable via the ordinary pooled path — direct-dial callers just won't be able to resolve it until a later publish succeeds. "Best-effort" still means the failure is logged, not silently discarded — a caller that only ever calls this once (never retries) has no other way to learn its handler is pooled-only, and "a later publish succeeds" cannot happen if nothing ever tries again.
-spec advertise_direct(macula:pool(), macula:realm(), macula:procedure(), module(), term(), macula_identity:key_pair(), map()) -> {ok, pid()} | {error, term()}.
As advertise_direct/6, with Opts forwarded BOTH to advertise/6 (so announce/auth apply here too) and to macula_direct_dial:publish_advertisement/5 — e.g. cert_chain => ChainPem (leaf ++ org CA, PEM), so a verifying consumer's verify_cert_chain opt can check this advertiser's org/realm authorization (Slice 7c Direction B, managed realms only. See macula_direct_dial's module doc, "Trust model") — each side reads only the keys it recognizes, so one Opts map serves both.
-spec unadvertise(macula:pool(), macula:realm(), macula:procedure()) -> ok.
Stop advertising. Does not stop the factory supervisor returned by advertise/5,6 — callers that want to tear it down should exit(Sup, shutdown) themselves.