|
@@ -15,7 +15,7 @@
|
|
|
-module(emqx_misc).
|
|
-module(emqx_misc).
|
|
|
|
|
|
|
|
-export([merge_opts/2, start_timer/2, start_timer/3, cancel_timer/1,
|
|
-export([merge_opts/2, start_timer/2, start_timer/3, cancel_timer/1,
|
|
|
- proc_name/2, proc_stats/0, proc_stats/1, conn_proc_mng_policy/0]).
|
|
|
|
|
|
|
+ proc_name/2, proc_stats/0, proc_stats/1, conn_proc_mng_policy/1]).
|
|
|
|
|
|
|
|
%% @doc Merge options
|
|
%% @doc Merge options
|
|
|
-spec(merge_opts(list(), list()) -> list()).
|
|
-spec(merge_opts(list(), list()) -> list()).
|
|
@@ -62,24 +62,30 @@ proc_stats(Pid) ->
|
|
|
|
|
|
|
|
%% @doc Check self() process status against connection/session process management policy,
|
|
%% @doc Check self() process status against connection/session process management policy,
|
|
|
%% return `continue | hibernate | {shutdown, Reason}' accordingly.
|
|
%% return `continue | hibernate | {shutdown, Reason}' accordingly.
|
|
|
-%% `continue': There is nothing out of the ordinary
|
|
|
|
|
-%% `hibernate': Nothing to process in my mailbox (and since this check is triggered
|
|
|
|
|
|
|
+%% `continue': There is nothing out of the ordinary.
|
|
|
|
|
+%% `hibernate': Nothing to process in my mailbox, and since this check is triggered
|
|
|
%% by a timer, we assume it is a fat chance to continue idel, hence hibernate.
|
|
%% by a timer, we assume it is a fat chance to continue idel, hence hibernate.
|
|
|
-%% `shutdown': Some numbers (message queue length or heap size have hit the limit,
|
|
|
|
|
|
|
+%% `shutdown': Some numbers (message queue length or heap size have hit the limit),
|
|
|
%% hence shutdown for greater good (system stability).
|
|
%% hence shutdown for greater good (system stability).
|
|
|
--spec(conn_proc_mng_policy() -> continue | hibernate | {shutdown, _}).
|
|
|
|
|
-conn_proc_mng_policy() ->
|
|
|
|
|
- MaxMsgQueueLen = application:get_env(?APPLICATION, conn_max_msg_queue_len, ?DISABLED),
|
|
|
|
|
|
|
+-spec(conn_proc_mng_policy(#{message_queue_len := integer(),
|
|
|
|
|
+ total_heap_size := integer()
|
|
|
|
|
+ } | undefined) -> continue | hibernate | {shutdown, _}).
|
|
|
|
|
+conn_proc_mng_policy(#{message_queue_len := MaxMsgQueueLen,
|
|
|
|
|
+ total_heap_size := MaxTotalHeapSize
|
|
|
|
|
+ }) ->
|
|
|
Qlength = proc_info(message_queue_len),
|
|
Qlength = proc_info(message_queue_len),
|
|
|
Checks =
|
|
Checks =
|
|
|
- [{fun() -> is_enabled(MaxMsgQueueLen) andalso Qlength > MaxMsgQueueLen end,
|
|
|
|
|
|
|
+ [{fun() -> is_message_queue_too_long(Qlength, MaxMsgQueueLen) end,
|
|
|
{shutdown, message_queue_too_long}},
|
|
{shutdown, message_queue_too_long}},
|
|
|
- {fun() -> is_heap_size_too_large() end,
|
|
|
|
|
|
|
+ {fun() -> is_heap_size_too_large(MaxTotalHeapSize) end,
|
|
|
{shutdown, total_heap_size_too_large}},
|
|
{shutdown, total_heap_size_too_large}},
|
|
|
{fun() -> Qlength > 0 end, continue},
|
|
{fun() -> Qlength > 0 end, continue},
|
|
|
{fun() -> true end, hibernate}
|
|
{fun() -> true end, hibernate}
|
|
|
],
|
|
],
|
|
|
- check(Checks).
|
|
|
|
|
|
|
+ check(Checks);
|
|
|
|
|
+conn_proc_mng_policy(_) ->
|
|
|
|
|
+ %% disable by default
|
|
|
|
|
+ conn_proc_mng_policy(#{message_queue_len => 0, total_heap_size => 0}).
|
|
|
|
|
|
|
|
check([{Pred, Result} | Rest]) ->
|
|
check([{Pred, Result} | Rest]) ->
|
|
|
case Pred() of
|
|
case Pred() of
|
|
@@ -87,11 +93,13 @@ check([{Pred, Result} | Rest]) ->
|
|
|
false -> check(Rest)
|
|
false -> check(Rest)
|
|
|
end.
|
|
end.
|
|
|
|
|
|
|
|
-is_heap_size_too_large() ->
|
|
|
|
|
- MaxTotalHeapSize = application:get_env(?APPLICATION, conn_max_total_heap_size, ?DISABLED),
|
|
|
|
|
- is_enabled(MaxTotalHeapSize) andalso proc_info(total_heap_size) > MaxTotalHeapSize.
|
|
|
|
|
|
|
+is_message_queue_too_long(Qlength, Max) ->
|
|
|
|
|
+ is_enabled(Max) andalso Qlength > Max.
|
|
|
|
|
|
|
|
-is_enabled(Max) -> Max > ?DISABLED.
|
|
|
|
|
|
|
+is_heap_size_too_large(Max) ->
|
|
|
|
|
+ is_enabled(Max) andalso proc_info(total_heap_size) > Max.
|
|
|
|
|
+
|
|
|
|
|
+is_enabled(Max) -> is_integer(Max) andalso Max > ?DISABLED.
|
|
|
|
|
|
|
|
proc_info(Key) ->
|
|
proc_info(Key) ->
|
|
|
{Key, Value} = erlang:process_info(self(), Key),
|
|
{Key, Value} = erlang:process_info(self(), Key),
|