1%% This Source Code Form is subject to the terms of the Mozilla Public 2%% License, v. 2.0. If a copy of the MPL was not distributed with this 3%% file, You can obtain one at https://mozilla.org/MPL/2.0/. 4%% 5%% Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. 6%% 7 8-module(rabbit_shovel_status). 9-behaviour(gen_server). 10 11-export([start_link/0]). 12 13-export([report/3, remove/1, status/0, lookup/1]). 14 15-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 16 terminate/2, code_change/3]). 17 18-define(SERVER, ?MODULE). 19-define(ETS_NAME, ?MODULE). 20-define(CHECK_FREQUENCY, 60000). 21 22-record(state, {timer}). 23-record(entry, {name, type, info, timestamp}). 24 25start_link() -> 26 gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). 27 28report(Name, Type, Info) -> 29 gen_server:cast(?SERVER, {report, Name, Type, Info, calendar:local_time()}). 30 31remove(Name) -> 32 gen_server:cast(?SERVER, {remove, Name}). 33 34status() -> 35 gen_server:call(?SERVER, status, infinity). 36 37lookup(Name) -> 38 gen_server:call(?SERVER, {lookup, Name}, infinity). 39 40init([]) -> 41 ?ETS_NAME = ets:new(?ETS_NAME, 42 [named_table, {keypos, #entry.name}, private]), 43 {ok, ensure_timer(#state{})}. 44 45handle_call(status, _From, State) -> 46 Entries = ets:tab2list(?ETS_NAME), 47 {reply, [{Entry#entry.name, Entry#entry.type, Entry#entry.info, 48 Entry#entry.timestamp} 49 || Entry <- Entries], State}; 50 51handle_call({lookup, Name}, _From, State) -> 52 Link = case ets:lookup(?ETS_NAME, Name) of 53 [Entry] -> [{name, Name}, 54 {type, Entry#entry.type}, 55 {info, Entry#entry.info}, 56 {timestamp, Entry#entry.timestamp}]; 57 [] -> not_found 58 end, 59 {reply, Link, State}. 60 61handle_cast({report, Name, Type, Info, Timestamp}, State) -> 62 true = ets:insert(?ETS_NAME, #entry{name = Name, type = Type, info = Info, 63 timestamp = Timestamp}), 64 rabbit_event:notify(shovel_worker_status, 65 split_name(Name) ++ split_status(Info)), 66 {noreply, State}; 67 68handle_cast({remove, Name}, State) -> 69 true = ets:delete(?ETS_NAME, Name), 70 rabbit_event:notify(shovel_worker_removed, split_name(Name)), 71 {noreply, State}. 72 73handle_info(check, State) -> 74 rabbit_shovel_dyn_worker_sup_sup:cleanup_specs(), 75 {noreply, ensure_timer(State)}; 76handle_info(_Info, State) -> 77 {noreply, State}. 78 79terminate(_Reason, State) -> 80 rabbit_misc:stop_timer(State, #state.timer), 81 ok. 82 83code_change(_OldVsn, State, _Extra) -> 84 {ok, State}. 85 86split_status({running, MoreInfo}) -> [{status, running} | MoreInfo]; 87split_status({terminated, Reason}) -> [{status, terminated}, 88 {reason, Reason}]; 89split_status(Status) when is_atom(Status) -> [{status, Status}]. 90 91split_name({VHost, Name}) -> [{name, Name}, 92 {vhost, VHost}]; 93split_name(Name) when is_atom(Name) -> [{name, Name}]. 94 95ensure_timer(State0) -> 96 State1 = rabbit_misc:stop_timer(State0, #state.timer), 97 rabbit_misc:ensure_timer(State1, #state.timer, ?CHECK_FREQUENCY, check). 98