Current section
Files
Jump to
Current section
Files
src/singleflight.erl
-module(singleflight).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/singleflight.gleam").
-export([config/2, fetch/3, start/2]).
-export_type([config/0, message/2, singleflight/2, state/2]).
-type config() :: {config, integer(), integer()}.
-type message(FLZ, FMA) :: {request,
FLZ,
fun((FLZ) -> FMA),
gleam@erlang@process:subject(FMA)} |
{done, FLZ, FMA}.
-opaque singleflight(FMB, FMC) :: {singleflight,
gleam@erlang@process:subject(message(FMB, FMC)),
integer()}.
-type state(FMD, FME) :: {state,
gleam@dict:dict(FMD, list(gleam@erlang@process:subject(FME))),
gleam@erlang@process:subject(message(FMD, FME))}.
-file("src/singleflight.gleam", 26).
-spec config(integer(), integer()) -> config().
config(Initialisation_timeout_ms, Fetch_timeout_ms) ->
{config, Initialisation_timeout_ms, Fetch_timeout_ms}.
-file("src/singleflight.gleam", 52).
-spec fetch(singleflight(FMN, FMO), FMN, fun((FMN) -> FMO)) -> FMO.
fetch(Singleflight, Key, Work) ->
{singleflight, Subject, Fetch_timeout_ms} = Singleflight,
gleam@otp@actor:call(
Subject,
Fetch_timeout_ms,
fun(Caller) -> {request, Key, Work, Caller} end
).
-file("src/singleflight.gleam", 60).
-spec handle_message(state(FMR, FMS), message(FMR, FMS)) -> gleam@otp@actor:next(state(FMR, FMS), message(FMR, FMS)).
handle_message(State, Message) ->
case Message of
{request, Key, Work, Caller} ->
case gleam_stdlib:map_get(erlang:element(2, State), Key) of
{ok, Waiters} ->
gleam@otp@actor:continue(
{state,
gleam@dict:insert(
erlang:element(2, State),
Key,
[Caller | Waiters]
),
erlang:element(3, State)}
);
{error, nil} ->
Self = erlang:element(3, State),
proc_lib:spawn_link(
fun() ->
Result = Work(Key),
gleam@otp@actor:send(Self, {done, Key, Result})
end
),
gleam@otp@actor:continue(
{state,
gleam@dict:insert(
erlang:element(2, State),
Key,
[Caller]
),
erlang:element(3, State)}
)
end;
{done, Key@1, Result@1} ->
case gleam_stdlib:map_get(erlang:element(2, State), Key@1) of
{ok, Waiters@1} ->
gleam@list:each(
Waiters@1,
fun(Waiter) ->
gleam@erlang@process:send(Waiter, Result@1)
end
);
{error, nil} ->
nil
end,
gleam@otp@actor:continue(
{state,
gleam@dict:delete(erlang:element(2, State), Key@1),
erlang:element(3, State)}
)
end.
-file("src/singleflight.gleam", 33).
-spec start(config(), gleam@erlang@process:name(message(FMF, FMG))) -> {ok,
gleam@otp@actor:started(singleflight(FMF, FMG))} |
{error, gleam@otp@actor:start_error()}.
start(Config, Name) ->
{config, Initialisation_timeout_ms, Fetch_timeout_ms} = Config,
_pipe@2 = gleam@otp@actor:new_with_initialiser(
Initialisation_timeout_ms,
fun(Self) ->
_pipe = gleam@otp@actor:initialised({state, maps:new(), Self}),
_pipe@1 = gleam@otp@actor:returning(
_pipe,
{singleflight, Self, Fetch_timeout_ms}
),
{ok, _pipe@1}
end
),
_pipe@3 = gleam@otp@actor:on_message(_pipe@2, fun handle_message/2),
_pipe@4 = gleam@otp@actor:named(_pipe@3, Name),
gleam@otp@actor:start(_pipe@4).