Current section
Files
Jump to
Current section
Files
src/throttle.erl
%% @author Coowry Developers Team
%%
%% @copyright 2018 Coowry Ltd. - All rights reserved.
%%
%% See LICENSE.txt file for detailed information.
%%
%% @doc This module is a supervisor for the context gen_servers.
%% This module has the functions to interact with the other modules.
%% IMPORTANT: You are only able to star one throttle supervisor.
-module(throttle).
%% Includes
-behaviour(supervisor).
%% Exports
-export([start_link/0, start_context/2, check/2, check/3,
stop/1, stop/0, peek/2, restore/2, restart/1,
get/0, get/1, get/2, init/1]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Public functions
%% @doc Start the supervisor.
-spec start_link() -> supervisor:startlink_ret().
start_link() ->
process_flag(trap_exit, true),
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%% @doc Create the context gen_server process, the function receive the Id
%% of the context and the parameters to create throttle_counter.
-spec start_context(Id :: atom(),
CounterInit :: {integer(), integer()}) -> {ok, pid()}.
start_context(Id, {Limit, Timeout}) ->
ChildSpec = #{id => Id,
start => {throttle_context, start_link, [Id, {Limit, Timeout}]},
restart => permanent,
shutdown => 10500,
type => worker,
modules => [throttle_context]
},
supervisor:start_child(?MODULE, ChildSpec).
%% @doc Update the counter of the CounterId belonging to the context
%% ContextId, and return a pair {ok, count} if you are between the limit or
%% {error | warning, counter, timeout} if you exceed the limit.
%% Throw 'invalid_context' if the context doesn't exist.
-spec check(atom(), any()) -> {ok, integer()} | {warning | error, integer(), integer()}.
check(ContextId, CounterId) ->
check(ContextId, CounterId, [{strict, false}]).
%% @doc Update the counter of the CounterId belonging to the context
%% ContextId, and return a pair {ok, count} if you are between the limit or
%% {error | warning, counter, timeout} if you exceed the limit.
%% Also include a option parameter.
%% Throw 'invalid_context' if the context doesn't exist.
-spec check(atom(), any(), [{atom(), boolean()}]) -> {ok, integer()} | {warning | error, integer(), integer()}.
check(ContextId, CounterId, Options) ->
try
throttle_context:check(ContextId, CounterId, Options)
catch
exit:_ -> throw(invalid_context)
end.
%% @doc Get the counter of the CounterId belonging to the context
%% ContextId and return a pair {ok, count} if you are between the limit or
%% {error | warning, counter, timeout} if you exceed the limit.
-spec peek(atom(), any()) -> {ok, integer()} | {warning | error, integer(), integer()}.
peek(ContextId, CounterId) ->
try
throttle_context:peek(ContextId, CounterId)
catch
exit:_ -> throw(invalid_context)
end.
%% @doc Restore the counter of the CounterId belonging to the context
%% ContextId and return a pair {ok, count}.
-spec restore(atom(), any()) -> {ok, integer()}.
restore(ContextId, CounterId) ->
try
throttle_context:restore(ContextId, CounterId)
catch
exit:_ -> throw(invalid_context)
end.
%% @doc Restart the context gen_server process independently of the state.
-spec restart(atom()) -> ok.
restart(ContextId) ->
try
case whereis(ContextId) of
undefined -> throw(invalid_context);
A ->
unlink(A),
throttle_context:stop(ContextId)
end
catch
exit:_ -> throw(invalid_context)
end.
%% @doc Stop the context gen_server process independently of the state.
-spec stop(atom() | pid()) -> ok.
stop(ContextId) when is_atom(ContextId) ->
supervisor:terminate_child(?MODULE, ContextId),
case supervisor:delete_child(?MODULE, ContextId) of
{error, _} -> throw(invalid_context);
_ -> ok
end;
stop(ContextId) when is_pid(ContextId) ->
case process_info(ContextId, registered_name) of
{registered_name, Name} ->
stop(Name);
_ -> throw(invalid_context)
end.
%% @doc Stop the throttle supervisor process independently of the state.
-spec stop() -> true.
stop() ->
exit(whereis(?MODULE), shutdown).
%% @doc Get information about a Counter inside of a Context.
-spec get(atom(), any()) -> #{id => atom(),
count => integer(),
blocked => boolean()}.
get(ContextId, CounterId) ->
try
throttle_context:get(ContextId, CounterId)
catch
exit:_ -> throw(invalid_context)
end.
%% @doc Get information about all the Counters inide of a context.
-spec get(atom()) -> [#{id => atom(),
count => integer(),
blocked => boolean()}].
get(Context) ->
try
throttle_context:get(Context)
catch
exit:_ -> throw(invalid_context)
end.
%% @doc Get all the Throttling informaticon about the counters and contexts.
-spec get() -> [{atom(), [#{id => atom(),
count => integer(),
blocked => boolean()}]}].
get() ->
Childs = supervisor:which_children(?MODULE),
lists:map(fun ({Name, Pid, _, _}) ->
try
{Name, throttle_context:get(Pid)}
catch
_:_ -> {Name, []}
end
end, Childs).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% supervisor functions
%% @doc Constructor of the throttle supervisor process.
init([]) ->
MaxRestart = 6,
MaxTime = 3000,
{ok, {{one_for_one, MaxRestart, MaxTime}, []}}.