1 |
|
%% Cleaning is triggered from all MongooseIM nodes. |
2 |
|
%% Though, it's quick, if there is nothing to remove. |
3 |
|
-module(mongoose_domain_db_cleaner). |
4 |
|
-include("mongoose_logger.hrl"). |
5 |
|
|
6 |
|
-export([start/1, stop/0]). |
7 |
|
-export([start_link/1]). |
8 |
|
|
9 |
|
%% gen_server callbacks |
10 |
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, |
11 |
|
terminate/2, code_change/3]). |
12 |
|
|
13 |
|
-ignore_xref([code_change/3, handle_call/3, handle_cast/2, handle_info/2, init/1, |
14 |
|
start_link/1, terminate/2]). |
15 |
|
|
16 |
|
%% --------------------------------------------------------------------------- |
17 |
|
%% Config |
18 |
|
|
19 |
|
%% --------------------------------------------------------------------------- |
20 |
|
%% Client code |
21 |
|
|
22 |
|
-spec start(mongoose_service:options()) -> ok. |
23 |
|
start(Opts) -> |
24 |
:-( |
ChildSpec = |
25 |
|
{?MODULE, |
26 |
|
{?MODULE, start_link, [Opts]}, |
27 |
|
permanent, infinity, worker, [?MODULE]}, |
28 |
:-( |
supervisor:start_child(ejabberd_sup, ChildSpec), |
29 |
:-( |
ok. |
30 |
|
|
31 |
|
-spec stop() -> ok. |
32 |
|
stop() -> |
33 |
:-( |
supervisor:terminate_child(ejabberd_sup, ?MODULE), |
34 |
:-( |
supervisor:delete_child(ejabberd_sup, ?MODULE), |
35 |
:-( |
ok. |
36 |
|
|
37 |
|
start_link(Opts) -> |
38 |
:-( |
gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). |
39 |
|
|
40 |
|
%% --------------------------------------------------------------------------- |
41 |
|
%% Server callbacks |
42 |
|
|
43 |
|
init(#{event_cleaning_interval := Interval, event_max_age := MaxAge}) -> |
44 |
:-( |
?LOG_INFO(#{what => domain_cleaner_start, cleaning_interval => Interval, max_age => MaxAge}), |
45 |
:-( |
State = #{max_age => MaxAge}, |
46 |
:-( |
self() ! schedule_removal, |
47 |
:-( |
timer:send_interval(timer:seconds(Interval), schedule_removal), |
48 |
:-( |
{ok, State}. |
49 |
|
|
50 |
|
handle_call(Request, From, State) -> |
51 |
:-( |
?UNEXPECTED_CALL(Request, From), |
52 |
:-( |
{reply, ok, State}. |
53 |
|
|
54 |
|
handle_cast(Msg, State) -> |
55 |
:-( |
?UNEXPECTED_CAST(Msg), |
56 |
:-( |
{noreply, State}. |
57 |
|
|
58 |
|
handle_info(schedule_removal, State) -> |
59 |
:-( |
{noreply, schedule_removal(State)}; |
60 |
|
handle_info({timeout, TimerRef, Msg}, State) -> |
61 |
:-( |
{noreply, handle_timeout(TimerRef, Msg, State)}; |
62 |
|
handle_info(Info, State) -> |
63 |
:-( |
?UNEXPECTED_INFO(Info), |
64 |
:-( |
{noreply, State}. |
65 |
|
|
66 |
|
terminate(_Reason, _State) -> |
67 |
:-( |
ok. |
68 |
|
|
69 |
|
code_change(_OldVsn, State, _Extra) -> |
70 |
:-( |
{ok, State}. |
71 |
|
|
72 |
|
%% --------------------------------------------------------------------------- |
73 |
|
%% Server helpers |
74 |
|
|
75 |
|
%% We are ensuring that to remove events, they have to be in the database |
76 |
|
%% for some amount of time |
77 |
|
schedule_removal(State = #{max_age := MaxAge}) -> |
78 |
:-( |
try mongoose_domain_sql:get_minmax_event_id() of |
79 |
|
{_Min, LastEventId} -> |
80 |
:-( |
Msg = {do_removal, LastEventId}, |
81 |
:-( |
erlang:start_timer(timer:seconds(MaxAge), self(), Msg) |
82 |
|
catch Class:Reason:Stacktrace -> |
83 |
|
%% It's safe to skip scheduling |
84 |
:-( |
?LOG_ERROR(#{what => domain_cleaning_schedule_failed, |
85 |
|
text => <<"Failed to get LastEventId">>, |
86 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}) |
87 |
|
end, |
88 |
:-( |
State. |
89 |
|
|
90 |
|
handle_timeout(_TimerRef, {do_removal, LastEventId}, State) -> |
91 |
:-( |
mongoose_domain_sql:delete_events_older_than(LastEventId), |
92 |
:-( |
State. |