livery_service (livery v0.1.0)

View Source

Service runtime.

Brings up H3 on UDP, H2 on TLS, and H1 on TCP under one supervisor, sharing one router/middleware/handler. Optionally advertises Alt-Svc on H1 and H2 responses so clients race up to H3.

Configuration map:

livery:start_service(#{
    host       => <<"example.com">>,
    http3      => #{port => 443, cert => Cert, key => Key},
    https      => #{port => 443, cert => Cert, key => Key},
    http       => #{port => 80},
    handler    => fun handler/1,
    middleware => Stack,
    alt_svc    => advertise
}).

Supply exactly one of handler (a single catch-all) or router (a compiled livery_router the service dispatches through, via livery:router_handler/1).

Returns {ok, ServicePid}. The service pid owns the listeners and shuts them down when stopped via livery:stop_service/1. A crash takes them all down together. For a polite shutdown that lets in-flight requests finish, use livery:drain/1,2.

Summary

Functions

Start a service from a config map.

Stop a running service.

Stop the service's listeners (no new connections) while leaving the gen_server and any in-flight requests running. Used by livery_drain to begin a graceful shutdown.

Return the ports the service is bound to, by protocol. Keys are present only for protocols that were configured.

Types

listener_opts()

-type listener_opts() ::
          #{port => inet:port_number(),
            cert => binary() | string(),
            key => binary() | string() | term(),
            cacerts => [binary()],
            acceptors => pos_integer(),
            settings => map(),
            quic_opts => map()}.

service_opts()

-type service_opts() ::
          #{host => binary(),
            http => listener_opts(),
            https => listener_opts(),
            http3 => listener_opts(),
            handler => livery_middleware:handler(),
            router => livery_router:router(),
            middleware => livery_middleware:stack(),
            alt_svc => advertise | none}.

Functions

code_change/3

-spec code_change(term(),
                  #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                         h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                         h3 :: {livery_h3:listener(), inet:port_number()} | undefined},
                  term()) ->
                     {ok,
                      #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                             h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                             h3 :: {livery_h3:listener(), inet:port_number()} | undefined}}.

handle_call/3

-spec handle_call(term(),
                  {pid(), term()},
                  #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                         h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                         h3 :: {livery_h3:listener(), inet:port_number()} | undefined}) ->
                     {reply,
                      term(),
                      #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                             h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                             h3 :: {livery_h3:listener(), inet:port_number()} | undefined}}.

handle_cast/2

-spec handle_cast(term(),
                  #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                         h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                         h3 :: {livery_h3:listener(), inet:port_number()} | undefined}) ->
                     {noreply,
                      #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                             h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                             h3 :: {livery_h3:listener(), inet:port_number()} | undefined}}.

handle_info/2

-spec handle_info(term(),
                  #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                         h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                         h3 :: {livery_h3:listener(), inet:port_number()} | undefined}) ->
                     {noreply,
                      #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                             h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                             h3 :: {livery_h3:listener(), inet:port_number()} | undefined}}.

init(Opts)

-spec init(service_opts()) ->
              {ok,
               #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                      h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                      h3 :: {livery_h3:listener(), inet:port_number()} | undefined}} |
              {stop, term()}.

start_link(Opts)

-spec start_link(service_opts()) -> {ok, pid()} | {error, term()}.

Start a service from a config map.

stop(Pid)

-spec stop(pid()) -> ok.

Stop a running service.

stop_accepting(Pid)

-spec stop_accepting(pid()) -> ok.

Stop the service's listeners (no new connections) while leaving the gen_server and any in-flight requests running. Used by livery_drain to begin a graceful shutdown.

terminate(Reason, State)

-spec terminate(term(),
                #state{h1 :: {livery_h1:listener(), inet:port_number()} | undefined,
                       h2 :: {livery_h2:listener(), inet:port_number()} | undefined,
                       h3 :: {livery_h3:listener(), inet:port_number()} | undefined}) ->
                   ok.

which_listeners(Pid)

-spec which_listeners(pid()) -> #{h1 | h2 | h3 => inet:port_number()}.

Return the ports the service is bound to, by protocol. Keys are present only for protocols that were configured.