Packages
Typed distributed messaging for Gleam on the BEAM.
Retired package: Deprecated - The project needs to be redesigned around a much smaller and clearer core.
Current section
Files
Jump to
Current section
Files
src/distribute@sugar.erl
-module(distribute@sugar).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/distribute/sugar.gleam").
-export([lookup_and_send/3, send_with_retry/4, receive_with_retry/4, request/5]).
-export_type([request_error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type request_error() :: registration_failed |
{send_failed, distribute@messaging:send_error()} |
{receive_failed, distribute@receiver:receive_error()}.
-file("src/distribute/sugar.gleam", 16).
?DOC(
" Look up a global name and send a typed message in one operation.\n"
" This is more efficient than separate lookup + send.\n"
).
-spec lookup_and_send(
binary(),
ODV,
fun((ODV) -> {ok, bitstring()} | {error, distribute@codec:encode_error()})
) -> {ok, nil} | {error, distribute@messaging:send_error()}.
lookup_and_send(Name, Msg, Encoder) ->
distribute@messaging:send_global_typed(Name, Msg, Encoder).
-file("src/distribute/sugar.gleam", 34).
-spec do_send_with_retry(
gleam@erlang@process:subject(bitstring()),
OEF,
fun((OEF) -> {ok, bitstring()} | {error, distribute@codec:encode_error()}),
integer(),
integer()
) -> {ok, nil} | {error, distribute@messaging:send_error()}.
do_send_with_retry(Subject, Msg, Encoder, Max_attempts, Attempt) ->
case distribute@messaging:send_typed(Subject, Msg, Encoder) of
{ok, _} ->
{ok, nil};
{error, _} when Attempt < Max_attempts ->
gleam_erlang_ffi:sleep(100 * Attempt),
do_send_with_retry(Subject, Msg, Encoder, Max_attempts, Attempt + 1);
{error, Err} ->
{error, Err}
end.
-file("src/distribute/sugar.gleam", 25).
?DOC(" Send a typed message with automatic retry on failure.\n").
-spec send_with_retry(
gleam@erlang@process:subject(bitstring()),
OEA,
fun((OEA) -> {ok, bitstring()} | {error, distribute@codec:encode_error()}),
integer()
) -> {ok, nil} | {error, distribute@messaging:send_error()}.
send_with_retry(Subject, Msg, Encoder, Max_attempts) ->
do_send_with_retry(Subject, Msg, Encoder, Max_attempts, 1).
-file("src/distribute/sugar.gleam", 61).
-spec do_receive_with_retry(
gleam@erlang@process:subject(bitstring()),
fun((bitstring()) -> {ok, OEP} | {error, distribute@codec:decode_error()}),
integer(),
integer(),
integer()
) -> {ok, OEP} | {error, distribute@receiver:receive_error()}.
do_receive_with_retry(Subject, Decoder, Timeout_ms, Max_attempts, Attempt) ->
case distribute@receiver:receive_typed(Subject, Decoder, Timeout_ms) of
{ok, Msg} ->
{ok, Msg};
{error, _} when Attempt < Max_attempts ->
do_receive_with_retry(
Subject,
Decoder,
Timeout_ms,
Max_attempts,
Attempt + 1
);
{error, Err} ->
{error, Err}
end.
-file("src/distribute/sugar.gleam", 52).
?DOC(" Receive a typed message with timeout and automatic retry.\n").
-spec receive_with_retry(
gleam@erlang@process:subject(bitstring()),
fun((bitstring()) -> {ok, OEK} | {error, distribute@codec:decode_error()}),
integer(),
integer()
) -> {ok, OEK} | {error, distribute@receiver:receive_error()}.
receive_with_retry(Subject, Decoder, Timeout_ms, Max_attempts) ->
do_receive_with_retry(Subject, Decoder, Timeout_ms, Max_attempts, 1).
-file("src/distribute/sugar.gleam", 83).
?DOC(" Create a request-response pattern: send and wait for reply.\n").
-spec request(
binary(),
OET,
fun((OET) -> {ok, bitstring()} | {error, distribute@codec:encode_error()}),
fun((bitstring()) -> {ok, OEV} | {error, distribute@codec:decode_error()}),
integer()
) -> {ok, OEV} | {error, request_error()}.
request(Target, Request, Request_encoder, Response_decoder, Timeout_ms) ->
Reply_subject = distribute@global:new(
fun(_) -> {ok, <<>>} end,
Response_decoder
),
Temp_name = <<"request_"/utf8,
(gleam@string:inspect(erlang:self()))/binary>>,
gleam@result:'try'(
begin
_pipe = distribute@registry:register_typed(
Temp_name,
distribute@global:subject(Reply_subject)
),
gleam@result:map_error(_pipe, fun(_) -> registration_failed end)
end,
fun(_) ->
gleam@result:'try'(
begin
_pipe@1 = distribute@messaging:send_global_typed(
Target,
Request,
Request_encoder
),
gleam@result:map_error(
_pipe@1,
fun(Field@0) -> {send_failed, Field@0} end
)
end,
fun(_) ->
gleam@result:'try'(
begin
_pipe@2 = distribute@global:'receive'(
Reply_subject,
Timeout_ms
),
gleam@result:map_error(
_pipe@2,
fun(_) ->
{receive_failed,
{decode_error,
{decode_failed, <<"timeout"/utf8>>}}}
end
)
end,
fun(Response) ->
_ = distribute@registry:unregister(Temp_name),
{ok, Response}
end
)
end
)
end
).