|
|
@@ -15,7 +15,9 @@
|
|
|
-module(emqx_misc).
|
|
|
|
|
|
-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/1]).
|
|
|
+ proc_name/2, proc_stats/0, proc_stats/1]).
|
|
|
+
|
|
|
+-export([init_proc_mng_policy/1, conn_proc_mng_policy/1]).
|
|
|
|
|
|
%% @doc Merge options
|
|
|
-spec(merge_opts(list(), list()) -> list()).
|
|
|
@@ -60,32 +62,35 @@ proc_stats(Pid) ->
|
|
|
|
|
|
-define(DISABLED, 0).
|
|
|
|
|
|
+init_proc_mng_policy(Zone) ->
|
|
|
+ #{max_heap_size := MaxHeapSizeInBytes} = ShutdownPolicy =
|
|
|
+ emqx_zone:get_env(Zone, force_shutdown_policy),
|
|
|
+ MaxHeapSize = MaxHeapSizeInBytes div erlang:system_info(wordsize),
|
|
|
+ _ = erlang:process_flag(max_heap_size, MaxHeapSize), % zero is discarded
|
|
|
+ erlang:put(force_shutdown_policy, ShutdownPolicy),
|
|
|
+ ok.
|
|
|
+
|
|
|
%% @doc Check self() process status against connection/session process management policy,
|
|
|
%% 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
|
|
|
%% 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 hit the limit),
|
|
|
%% hence shutdown for greater good (system stability).
|
|
|
--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
|
|
|
- }) ->
|
|
|
+-spec(conn_proc_mng_policy(#{message_queue_len => integer()} | false) ->
|
|
|
+ continue | hibernate | {shutdown, _}).
|
|
|
+conn_proc_mng_policy(#{message_queue_len := MaxMsgQueueLen}) ->
|
|
|
Qlength = proc_info(message_queue_len),
|
|
|
Checks =
|
|
|
[{fun() -> is_message_queue_too_long(Qlength, MaxMsgQueueLen) end,
|
|
|
{shutdown, message_queue_too_long}},
|
|
|
- {fun() -> is_heap_size_too_large(MaxTotalHeapSize) end,
|
|
|
- {shutdown, total_heap_size_too_large}},
|
|
|
{fun() -> Qlength > 0 end, continue},
|
|
|
{fun() -> true end, hibernate}
|
|
|
],
|
|
|
check(Checks);
|
|
|
conn_proc_mng_policy(_) ->
|
|
|
%% disable by default
|
|
|
- conn_proc_mng_policy(#{message_queue_len => 0, total_heap_size => 0}).
|
|
|
+ conn_proc_mng_policy(#{message_queue_len => 0}).
|
|
|
|
|
|
check([{Pred, Result} | Rest]) ->
|
|
|
case Pred() of
|
|
|
@@ -96,9 +101,6 @@ check([{Pred, Result} | Rest]) ->
|
|
|
is_message_queue_too_long(Qlength, Max) ->
|
|
|
is_enabled(Max) andalso Qlength > Max.
|
|
|
|
|
|
-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) ->
|