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, request_delete_domain/2]). |
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 |
104 |
ChildSpec = |
25 |
|
{?MODULE, |
26 |
|
{?MODULE, start_link, [Opts]}, |
27 |
|
permanent, infinity, worker, [?MODULE]}, |
28 |
104 |
supervisor:start_child(ejabberd_sup, ChildSpec), |
29 |
104 |
ok. |
30 |
|
|
31 |
|
-spec stop() -> ok. |
32 |
|
stop() -> |
33 |
100 |
supervisor:terminate_child(ejabberd_sup, ?MODULE), |
34 |
100 |
supervisor:delete_child(ejabberd_sup, ?MODULE), |
35 |
100 |
ok. |
36 |
|
|
37 |
|
start_link(Opts) -> |
38 |
104 |
gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). |
39 |
|
|
40 |
|
-spec request_delete_domain(jid:lserver(), mongooseim:host_type()) -> ok. |
41 |
|
request_delete_domain(Domain, HostType) -> |
42 |
5 |
gen_server:cast(?MODULE, {delete_domain, Domain, HostType}). |
43 |
|
|
44 |
|
%% --------------------------------------------------------------------------- |
45 |
|
%% Server callbacks |
46 |
|
|
47 |
|
init(#{event_cleaning_interval := Interval, event_max_age := MaxAge}) -> |
48 |
104 |
?LOG_INFO(#{what => domain_cleaner_start, cleaning_interval => Interval, max_age => MaxAge}), |
49 |
104 |
State = #{max_age => MaxAge}, |
50 |
104 |
self() ! schedule_removal, |
51 |
104 |
timer:send_interval(timer:seconds(Interval), schedule_removal), |
52 |
104 |
{ok, State}. |
53 |
|
|
54 |
|
handle_call(Request, From, State) -> |
55 |
:-( |
?UNEXPECTED_CALL(Request, From), |
56 |
:-( |
{reply, ok, State}. |
57 |
|
|
58 |
|
handle_cast({delete_domain, Domain, HostType}, State) -> |
59 |
5 |
{noreply, handle_delete_domain(Domain, HostType, State)}; |
60 |
|
handle_cast(Msg, State) -> |
61 |
:-( |
?UNEXPECTED_CAST(Msg), |
62 |
:-( |
{noreply, State}. |
63 |
|
|
64 |
|
handle_info(schedule_removal, State) -> |
65 |
108 |
{noreply, schedule_removal(State)}; |
66 |
|
handle_info({timeout, TimerRef, Msg}, State) -> |
67 |
2 |
{noreply, handle_timeout(TimerRef, Msg, State)}; |
68 |
|
handle_info(Info, State) -> |
69 |
:-( |
?UNEXPECTED_INFO(Info), |
70 |
:-( |
{noreply, State}. |
71 |
|
|
72 |
|
terminate(_Reason, _State) -> |
73 |
:-( |
ok. |
74 |
|
|
75 |
|
code_change(_OldVsn, State, _Extra) -> |
76 |
:-( |
{ok, State}. |
77 |
|
|
78 |
|
%% --------------------------------------------------------------------------- |
79 |
|
%% Server helpers |
80 |
|
|
81 |
|
%% We are ensuring that to remove events, they have to be in the database |
82 |
|
%% for some amount of time |
83 |
|
schedule_removal(State = #{max_age := MaxAge}) -> |
84 |
108 |
try mongoose_domain_sql:get_minmax_event_id() of |
85 |
|
{_Min, LastEventId} -> |
86 |
108 |
Msg = {do_removal, LastEventId}, |
87 |
108 |
erlang:start_timer(timer:seconds(MaxAge), self(), Msg) |
88 |
|
catch Class:Reason:Stacktrace -> |
89 |
|
%% It's safe to skip scheduling |
90 |
:-( |
?LOG_ERROR(#{what => domain_cleaning_schedule_failed, |
91 |
|
text => <<"Failed to get LastEventId">>, |
92 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}) |
93 |
|
end, |
94 |
108 |
State. |
95 |
|
|
96 |
|
handle_timeout(_TimerRef, {do_removal, LastEventId}, State) -> |
97 |
2 |
mongoose_domain_sql:delete_events_older_than(LastEventId), |
98 |
2 |
State. |
99 |
|
|
100 |
|
handle_delete_domain(Domain, HostType, State) -> |
101 |
5 |
try |
102 |
5 |
mongoose_domain_api:do_delete_domain_in_progress(Domain, HostType) |
103 |
|
catch Class:Reason:Stacktrace -> |
104 |
:-( |
?LOG_ERROR(#{what => domain_deletion_failed, |
105 |
|
domain => Domain, host_type => HostType, |
106 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}) |
107 |
|
end, |
108 |
5 |
State. |