Переделать связь нод в кластере на автоматическое обнаружение #9

This commit is contained in:
2026-05-01 22:30:40 +03:00
parent 1787b0f8a3
commit f36dd3bbc1
25 changed files with 870 additions and 332 deletions

View File

@@ -1,3 +1,6 @@
-name ${NODE_NAME}
-sname ${NODE_NAME}
-setcookie ${RELEASE_COOKIE}
-kernel inet_dist_use_interface {0,0,0,0}
+K true
+A 8
-kernel inet_dist_listen_min 2370
-kernel inet_dist_listen_max 2370

View File

@@ -10,12 +10,19 @@ start(_StartType, _StartArgs) ->
{ok, Pid} ->
ok = infra_mnesia:init_tables(),
ok = infra_mnesia:wait_for_tables(),
connect_nodes(),
init_default_superadmin(),
% Включаем авто‑обнаружение только в режиме remote/swarm
ClusterMode = os:getenv("CLUSTER_MODE", "local"),
if ClusterMode =:= "swarm" orelse ClusterMode =:= "remote" ->
spawn(fun cluster_discovery:discover/0);
true ->
% Локальный запуск подключаемся по старинке или вообще не подключаемся
ok
end,
start_http(), % Пользовательский API (8080)
start_admin_http(), % Административный API (8445)
application:ensure_all_started(prometheus),
application:ensure_all_started(prometheus_cowboy),
init_default_admins(),
{ok, Pid};
Error ->
Error
@@ -114,34 +121,33 @@ start_admin_http() ->
io:format("WebSocket started on ports 8081 (user) and 8446 (admin)~n").
%% ===================================================================
%% Ручное подключение к нодам кластера (запасной вариант)
%% ===================================================================
connect_nodes() ->
case os:getenv("JOIN_NODES") of
false -> ok;
NodesStr ->
Nodes = [list_to_atom(string:trim(N)) || N <- string:tokens(NodesStr, ",")],
lists:foreach(fun(Node) ->
case net_kernel:connect_node(Node) of
true -> io:format("Connected to ~s~n", [Node]);
false -> io:format("ERROR: Failed to connect to ~s~n", [Node]);
ignored -> ok
end
end, Nodes)
end.
init_default_superadmin() ->
%% ---------- Инициализация администраторов ----------
init_default_admins() ->
case core_admin:list_all() of
[] ->
AdminEmail = os:getenv("ADMIN_EMAIL", "admin@eventhub.local"),
AdminPassword = os:getenv("ADMIN_PASSWORD", "123456"),
{ok, _Admin} = core_admin:create(
list_to_binary(AdminEmail),
list_to_binary(AdminPassword),
superadmin
),
io:format("Default superadmin created: ~s~n", [AdminEmail]);
% Суперадмин
SuperEmail = list_to_binary(os:getenv("ADMIN_SUPER_EMAIL", "superadmin2@eventhub.local")),
SuperPass = list_to_binary(os:getenv("ADMIN_SUPER_PASSWORD", "123456")),
{ok, _} = core_admin:create(SuperEmail, SuperPass, superadmin),
io:format("Default superadmin created: ~s~n", [SuperEmail]),
% Админ
AdminEmail = list_to_binary(os:getenv("ADMIN_EMAIL", "admin@eventhub.local")),
AdminPass = list_to_binary(os:getenv("ADMIN_PASSWORD", "123456")),
{ok, _} = core_admin:create(AdminEmail, AdminPass, admin),
io:format("Default admin created: ~s~n", [AdminEmail]),
% Модератор
ModerEmail = list_to_binary(os:getenv("ADMIN_MODER_EMAIL", "moderator@eventhub.local")),
ModerPass = list_to_binary(os:getenv("ADMIN_MODER_PASSWORD", "123456")),
{ok, _} = core_admin:create(ModerEmail, ModerPass, moderator),
io:format("Default moderator created: ~s~n", [ModerEmail]),
% Поддержка
SupportEmail = list_to_binary(os:getenv("ADMIN_SUPPORT_EMAIL", "support@eventhub.local")),
SupportPass = list_to_binary(os:getenv("ADMIN_SUPPORT_PASSWORD", "123456")),
{ok, _} = core_admin:create(SupportEmail, SupportPass, support),
io:format("Default support created: ~s~n", [SupportEmail]);
_ ->
io:format("Superadmin already exists. Skipping creation.~n")
io:format("Admins already exist. Skipping creation.~n")
end.

View File

@@ -30,6 +30,11 @@ get_permissions(superadmin) ->
<<"manage_calendars">>, <<"manage_reviews">>, <<"manage_reports">>,
<<"manage_tickets">>, <<"manage_banned_words">>, <<"view_stats">>,
<<"view_audit">>];
get_permissions(admin) ->
[<<"manage_users">>, <<"manage_events">>,
<<"manage_calendars">>, <<"manage_reviews">>, <<"manage_reports">>,
<<"manage_tickets">>, <<"manage_banned_words">>, <<"view_stats">>,
<<"view_audit">>];
get_permissions(moderator) ->
[<<"manage_events">>, <<"manage_calendars">>, <<"manage_reviews">>,
<<"manage_reports">>, <<"manage_tickets">>, <<"manage_banned_words">>,

View File

@@ -0,0 +1,36 @@
-module(cluster_discovery).
-export([discover/0]).
-define(DNS_ALIAS, "eventhub-node").
-define(RETRY_INTERVAL, 5000).
discover() ->
io:format("Starting cluster DNS discovery via epmd (~s)...~n", [?DNS_ALIAS]),
discover_loop().
discover_loop() ->
case inet:getaddrs(?DNS_ALIAS, inet) of
{ok, IPs} when is_list(IPs) ->
lists:foreach(fun(IP) ->
IPStr = inet:ntoa(IP),
%% io:format("Checking epmd on ~s...~n", [IPStr]),
case erl_epmd:names(IP) of
{ok, List} ->
lists:foreach(fun({Name, _Port}) ->
Node = list_to_atom(Name ++ "@" ++ Name),
%% io:format(" Trying net_kernel:connect_node(~s)...~n", [Node]),
case net_kernel:connect_node(Node) of
true -> ok; %io:format(" *** Connected to ~s ***~n", [Node]);
false -> io:format(" *** Failed to connect to ~s ***~n", [Node]);
ignored -> ok
end
end, List);
{error, Reason} ->
io:format(" epmd error on ~s: ~p~n", [IPStr, Reason])
end
end, IPs);
{error, Reason} ->
io:format("DNS lookup failed (~p), retrying...~n", [Reason])
end,
timer:sleep(?RETRY_INTERVAL),
discover_loop().