ekfa/src/docker/docker_deploy_manager.erl
2026-04-21 16:24:59 +08:00

93 lines
3.4 KiB
Erlang

%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2026, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 20. 4月 2026
%%%-------------------------------------------------------------------
-module(docker_deploy_manager).
-author("anlicheng").
-include("message_pb.hrl").
-behaviour(gen_server).
%% API
-export([start_link/0, deploy/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {
root_dir :: string(),
task_map = #{}
}).
%%%===================================================================
%%% API
%%%===================================================================
-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
-spec deploy(integer(), message_pb:'ContainerDeployParams'()) -> ok | {error, binary()}.
deploy(TaskId, Params) when is_integer(TaskId), is_record(Params, 'ContainerDeployParams') ->
gen_server:call(?SERVER, {deploy, TaskId, Params}).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
-spec init(list()) -> {ok, #state{}}.
init([]) ->
erlang:process_flag(trap_exit, true),
{ok, RootDir} = application:get_env(efka, root_dir),
{ok, #state{root_dir = RootDir}}.
-spec handle_call(term(), {pid(), term()}, #state{}) -> {reply, term(), #state{}}.
handle_call({deploy, TaskId, Params = #'ContainerDeployParams'{
container_name = ContainerName,
container_dir = ContainerDir0
}}, _From, State = #state{root_dir = RootDir, task_map = TaskMap}) ->
{ok, ContainerDir} = docker_helper:ensure_container_dir(RootDir, ContainerName, ContainerDir0),
{ok, {TaskPid, _Ref}} = docker_deployer:start_monitor(TaskId, ContainerDir, Params),
logger:debug("[docker_deploy_manager] start deploy task_id: ~p, params: ~p", [TaskId, Params]),
{reply, ok, State#state{task_map = maps:put(TaskPid, TaskId, TaskMap)}};
handle_call(_Request, _From, State) ->
{reply, ok, State}.
-spec handle_cast(term(), #state{}) -> {noreply, #state{}}.
handle_cast(_Request, State) ->
{noreply, State}.
-spec handle_info(term(), #state{}) -> {noreply, #state{}}.
handle_info({'DOWN', _Ref, process, TaskPid, Reason}, State = #state{task_map = TaskMap}) ->
case maps:take(TaskPid, TaskMap) of
error ->
{noreply, State};
{TaskId, NTaskMap} ->
case Reason of
normal ->
logger:debug("[docker_deploy_manager] task_id: ~p, exit normal", [TaskId]);
Error0 ->
Error = iolist_to_binary(io_lib:format("~p", [Error0])),
docker_task_reporter:stream(TaskId, <<"error">>, <<"任务失败: "/utf8, Error/binary>>),
docker_task_reporter:close(TaskId, <<"task exited">>),
logger:notice("[docker_deploy_manager] task_id: ~p, exit with error: ~p", [TaskId, Error])
end,
{noreply, State#state{task_map = NTaskMap}}
end;
handle_info(_Info, State) ->
{noreply, State}.
-spec terminate(term(), #state{}) -> ok.
terminate(_Reason, _State) ->
ok.
-spec code_change(term(), #state{}, term()) -> {ok, #state{}}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.