%% This Source Code Form is subject to the terms of the Mozilla Public %% License, v. 2.0. If a copy of the MPL was not distributed with this %% file, You can obtain one at https://mozilla.org/MPL/2.0/. %% %% Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. %% %% This module implements a vhost identity process. %% On start this process will try to recover the vhost data and %% processes structure (queues and message stores). %% If recovered successfully, the process will save it's PID %% to vhost process registry. If vhost process PID is in the registry and the %% process is alive - the vhost is considered running. %% On termination, the ptocess will notify of vhost going down. %% The process will also check periodically if the vhost still %% present in mnesia DB and stop the vhost supervision tree when it %% disappears. -module(rabbit_vhost_process). %% Transitional step until we can require Erlang/OTP 21 and %% use the now recommended try/catch syntax for obtaining the stack trace. -compile(nowarn_deprecated_function). -include("rabbit.hrl"). -define(TICKTIME_RATIO, 4). -behaviour(gen_server2). -export([start_link/1]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). start_link(VHost) -> gen_server2:start_link(?MODULE, [VHost], []). init([VHost]) -> process_flag(trap_exit, true), rabbit_log:debug("Recovering data for VHost ~p~n", [VHost]), try %% Recover the vhost data and save it to vhost registry. ok = rabbit_vhost:recover(VHost), rabbit_vhost_sup_sup:save_vhost_process(VHost, self()), Interval = interval(), timer:send_interval(Interval, check_vhost), true = erlang:garbage_collect(), {ok, VHost} catch _:Reason:Stacktrace -> rabbit_amqqueue:mark_local_durable_queues_stopped(VHost), rabbit_log:error("Unable to recover vhost ~p data. Reason ~p~n" " Stacktrace ~p", [VHost, Reason, Stacktrace]), {stop, Reason} end. handle_call(_,_,VHost) -> {reply, ok, VHost}. handle_cast(_, VHost) -> {noreply, VHost}. handle_info(check_vhost, VHost) -> case rabbit_vhost:exists(VHost) of true -> {noreply, VHost}; false -> rabbit_log:warning("Virtual host '~s' is gone. " "Stopping its top level supervisor.", [VHost]), %% Stop vhost's top supervisor in a one-off process to avoid a deadlock: %% us (a child process) waiting for supervisor shutdown and our supervisor(s) %% waiting for us to shutdown. spawn( fun() -> rabbit_vhost_sup_sup:stop_and_delete_vhost(VHost) end), {noreply, VHost} end; handle_info(_, VHost) -> {noreply, VHost}. terminate(shutdown, VHost) -> %% Notify that vhost is stopped. rabbit_vhost:vhost_down(VHost); terminate(_, _VHost) -> ok. code_change(_OldVsn, VHost, _Extra) -> {ok, VHost}. interval() -> application:get_env(kernel, net_ticktime, 60000) * ?TICKTIME_RATIO.