Current section

Files

Jump to
temporal_sdk src limiter temporal_sdk_limiter_os.erl
Raw

src/limiter/temporal_sdk_limiter_os.erl

-module(temporal_sdk_limiter_os).
-behaviour(gen_server).
% elp:ignore W0012 W0040
-moduledoc false.
-export([
setup/0,
get_stats/1
]).
-export([
start_link/2
]).
-export([
init/1,
handle_call/3,
handle_cast/2,
handle_continue/2,
handle_info/2
]).
-spec setup() ->
{
Counter :: temporal_sdk_limiter:counter(),
LimiterChiSpec :: supervisor:child_spec(),
DiskMounts :: [string()]
}.
setup() ->
C1 =
case erlang:whereis(cpu_sup) of
undefined ->
#{};
_PidCpu ->
#{
cpu1 => counters:new(1, []),
cpu5 => counters:new(1, []),
cpu15 => counters:new(1, [])
}
end,
Counters =
case erlang:whereis(memsup) of
undefined -> C1;
_PidMem -> C1#{mem => counters:new(1, [])}
end,
{UserCounters, DiskCounters, DiskMounts} =
case erlang:whereis(disksup) of
undefined ->
{Counters, [], []};
_PidDisk ->
DCZip = lists:map(
fun({Id, _Total, _Capacity}) ->
C = counters:new(1, []),
{{{disk, Id}, C}, {Id, C}, Id}
end,
disksup:get_disk_data()
),
{UDCounters, DCounters, DMounts} = lists:unzip3(DCZip),
{maps:merge(Counters, proplists:to_map(UDCounters)), DCounters, DMounts}
end,
ChiSpec = #{id => {?MODULE}, start => {?MODULE, start_link, [Counters, DiskCounters]}},
{UserCounters, ChiSpec, DiskMounts}.
-spec get_stats(Counter :: temporal_sdk_limiter:counter()) -> temporal_sdk_limiter:stats().
get_stats(Counter) -> maps:map(fun(_L, C) -> counters:get(C, 1) end, Counter).
%% -------------------------------------------------------------------------------------------------
%% gen_server
start_link(Counters, DiskCounters) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [Counters, DiskCounters], []).
init([Counters, DiskCounters]) ->
{ok, [], {continue, [Counters, DiskCounters]}}.
handle_continue([Counters, DiskCounters], []) ->
maps:foreach(
fun(L, _C) -> erlang:send_after(get_check_interval(init), self(), {update, L}) end, Counters
),
case DiskCounters of
[] -> ok;
[_ | _] -> erlang:send_after(get_check_interval(init), self(), {update, disk})
end,
{noreply, {Counters, DiskCounters}}.
handle_info({update, Limitable}, State) ->
case put(Limitable, get_data(Limitable), State) of
ok ->
erlang:send_after(get_check_interval(Limitable), self(), {update, Limitable}),
{noreply, State};
Err ->
{stop, Err, State}
end;
handle_info(_Info, State) ->
{stop, invalid_request, State}.
handle_call(_Request, _From, State) ->
{stop, invalid_request, State}.
handle_cast(_Request, State) ->
{stop, invalid_request, State}.
get_check_interval(Limitable) ->
do_get_check_interval(Limitable) + rand:uniform(10).
do_get_check_interval(init) -> 0;
do_get_check_interval(cpu1) -> 1_000;
do_get_check_interval(cpu5) -> 5_000;
do_get_check_interval(cpu15) -> 15_000;
do_get_check_interval(mem) -> memsup:get_check_interval();
do_get_check_interval(disk) -> disksup:get_check_interval().
get_data(cpu1) ->
case cpu_sup:avg1() of
0 -> -1;
V -> V
end;
get_data(cpu5) ->
case cpu_sup:avg5() of
0 -> -1;
V -> V
end;
get_data(cpu15) ->
case cpu_sup:avg15() of
0 -> -1;
V -> V
end;
get_data(mem) ->
case memsup:get_memory_data() of
{0, 0, _} -> -1;
{Total, Allocated, _Worst} -> round(Allocated / Total * 100)
end;
get_data(disk) ->
disksup:get_disk_data().
put(disk, Data, {Counters, [{Id, C} | TDiskCounters]}) ->
case lists:keyfind(Id, 1, Data) of
{Id, _, Capacity} when is_integer(Capacity), Capacity >= 0 -> counters:put(C, 1, Capacity);
_ -> counters:put(C, 1, -1)
end,
put(disk, Data, {Counters, TDiskCounters});
put(disk, _Data, {_Counters, []}) ->
ok;
put(Limitable, Value, {Counters, _DiskCounters}) ->
case Counters of
#{Limitable := C} -> counters:put(C, 1, Value);
_ -> {error, "Malformed state."}
end.