chore: add config leader to suggestion
This commit is contained in:
parent
22fc3c49cc
commit
bdf3fc63a6
|
@ -35,6 +35,17 @@
|
||||||
tnx_id :: pos_integer() | '$1'
|
tnx_id :: pos_integer() | '$1'
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
-define(SUGGESTION(Node),
|
||||||
|
lists:flatten(
|
||||||
|
io_lib:format(
|
||||||
|
"run `./bin/emqx_ctl conf cluster_sync fix`"
|
||||||
|
" on ~p(config leader) to force sync the configs,"
|
||||||
|
"when this node is lagging for more than 3 minutes,",
|
||||||
|
[Node]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
-define(READONLY_KEYS, [cluster, rpc, node]).
|
-define(READONLY_KEYS, [cluster, rpc, node]).
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
reset/0,
|
reset/0,
|
||||||
status/0,
|
status/0,
|
||||||
is_initiator/1,
|
is_initiator/1,
|
||||||
|
find_leader/0,
|
||||||
skip_failed_commit/1,
|
skip_failed_commit/1,
|
||||||
fast_forward_to_commit/2,
|
fast_forward_to_commit/2,
|
||||||
on_mria_stop/1,
|
on_mria_stop/1,
|
||||||
|
@ -227,6 +228,17 @@ status() ->
|
||||||
is_initiator(Opts) ->
|
is_initiator(Opts) ->
|
||||||
?KIND_INITIATE =:= maps:get(kind, Opts, ?KIND_INITIATE).
|
?KIND_INITIATE =:= maps:get(kind, Opts, ?KIND_INITIATE).
|
||||||
|
|
||||||
|
find_leader() ->
|
||||||
|
{atomic, Status} = status(),
|
||||||
|
case Status of
|
||||||
|
[#{node := N} | _] ->
|
||||||
|
N;
|
||||||
|
[] ->
|
||||||
|
%% running nodes already sort.
|
||||||
|
[N | _] = emqx:running_nodes(),
|
||||||
|
N
|
||||||
|
end.
|
||||||
|
|
||||||
%% DO NOT delete this on_leave_clean/0, It's use when rpc before v560.
|
%% DO NOT delete this on_leave_clean/0, It's use when rpc before v560.
|
||||||
on_leave_clean() ->
|
on_leave_clean() ->
|
||||||
on_leave_clean(node()).
|
on_leave_clean(node()).
|
||||||
|
@ -500,10 +512,11 @@ do_initiate(MFA, State = #{node := Node}, Count, Failure0) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stale_view_of_cluster_msg(Meta, Count) ->
|
stale_view_of_cluster_msg(Meta, Count) ->
|
||||||
|
Node = find_leader(),
|
||||||
Reason = Meta#{
|
Reason = Meta#{
|
||||||
msg => stale_view_of_cluster,
|
msg => stale_view_of_cluster,
|
||||||
retry_times => Count,
|
retry_times => Count,
|
||||||
suggested => "run `./bin/emqx_ctl conf cluster_sync fix` when suck for a long time"
|
suggestion => ?SUGGESTION(Node)
|
||||||
},
|
},
|
||||||
?SLOG(warning, Reason),
|
?SLOG(warning, Reason),
|
||||||
{error, Reason}.
|
{error, Reason}.
|
||||||
|
@ -537,7 +550,7 @@ transaction(Func, Args) ->
|
||||||
mria:transaction(?CLUSTER_RPC_SHARD, Func, Args).
|
mria:transaction(?CLUSTER_RPC_SHARD, Func, Args).
|
||||||
|
|
||||||
trans_status() ->
|
trans_status() ->
|
||||||
mnesia:foldl(
|
List = mnesia:foldl(
|
||||||
fun(Rec, Acc) ->
|
fun(Rec, Acc) ->
|
||||||
#cluster_rpc_commit{node = Node, tnx_id = TnxId} = Rec,
|
#cluster_rpc_commit{node = Node, tnx_id = TnxId} = Rec,
|
||||||
case mnesia:read(?CLUSTER_MFA, TnxId) of
|
case mnesia:read(?CLUSTER_MFA, TnxId) of
|
||||||
|
@ -560,6 +573,12 @@ trans_status() ->
|
||||||
end,
|
end,
|
||||||
[],
|
[],
|
||||||
?CLUSTER_COMMIT
|
?CLUSTER_COMMIT
|
||||||
|
),
|
||||||
|
lists:sort(
|
||||||
|
fun(#{node := NA, tnx_id := IdA}, #{node := NB, tnx_id := IdB}) ->
|
||||||
|
{IdA, NA} > {IdB, NB}
|
||||||
|
end,
|
||||||
|
List
|
||||||
).
|
).
|
||||||
|
|
||||||
trans_query(TnxId) ->
|
trans_query(TnxId) ->
|
||||||
|
|
|
@ -96,15 +96,23 @@ admins(["inspect", TnxId0]) ->
|
||||||
TnxId = list_to_integer(TnxId0),
|
TnxId = list_to_integer(TnxId0),
|
||||||
print(emqx_cluster_rpc:query(TnxId));
|
print(emqx_cluster_rpc:query(TnxId));
|
||||||
admins(["fix"]) ->
|
admins(["fix"]) ->
|
||||||
|
{atomic, Status} = emqx_cluster_rpc:status(),
|
||||||
case mria_rlog:role() of
|
case mria_rlog:role() of
|
||||||
core ->
|
core ->
|
||||||
{atomic, Status} = emqx_cluster_rpc:status(),
|
|
||||||
#{stopped_nodes := StoppedNodes} = emqx_mgmt_cli:cluster_info(),
|
#{stopped_nodes := StoppedNodes} = emqx_mgmt_cli:cluster_info(),
|
||||||
maybe_fix_inconsistent(Status, #{fix => true}),
|
maybe_fix_inconsistent(Status, #{fix => true}),
|
||||||
StoppedNodes =/= [] andalso
|
StoppedNodes =/= [] andalso
|
||||||
emqx_ctl:warning("Found stopped nodes: ~p~n", [StoppedNodes]);
|
emqx_ctl:warning("Found stopped nodes: ~p~n", [StoppedNodes]);
|
||||||
Role ->
|
Role ->
|
||||||
emqx_ctl:print("Run fix command on core node, but current is ~p~n", [Role])
|
Core =
|
||||||
|
case find_highest_node(Status) of
|
||||||
|
{same_tnx_id, _TnxId} ->
|
||||||
|
{ok, Node} = mria_status:upstream_node(?CLUSTER_RPC_SHARD),
|
||||||
|
Node;
|
||||||
|
{ok, Node} ->
|
||||||
|
Node
|
||||||
|
end,
|
||||||
|
emqx_ctl:print("Run fix command on ~p(core) node, but current is ~p~n", [Core, Role])
|
||||||
end;
|
end;
|
||||||
admins(["fast_forward"]) ->
|
admins(["fast_forward"]) ->
|
||||||
status(),
|
status(),
|
||||||
|
@ -128,7 +136,14 @@ admins(_) ->
|
||||||
emqx_ctl:usage(usage_sync()).
|
emqx_ctl:usage(usage_sync()).
|
||||||
|
|
||||||
fix_inconsistent_with_raw(Node, Keys) ->
|
fix_inconsistent_with_raw(Node, Keys) ->
|
||||||
Confs = [#{Key => emqx_conf_proto_v4:get_raw_config(Node, Key)} || Key <- Keys],
|
Confs = lists:foldl(
|
||||||
|
fun(Key, Acc) ->
|
||||||
|
KeyRaw = atom_to_binary(Key),
|
||||||
|
Acc#{KeyRaw => emqx_conf_proto_v4:get_raw_config(Node, [Key])}
|
||||||
|
end,
|
||||||
|
#{},
|
||||||
|
Keys
|
||||||
|
),
|
||||||
ok = emqx_cluster_rpc:reset(),
|
ok = emqx_cluster_rpc:reset(),
|
||||||
case load_config_from_raw(Confs, #{mode => replace}) of
|
case load_config_from_raw(Confs, #{mode => replace}) of
|
||||||
ok -> waiting_for_fix_finish();
|
ok -> waiting_for_fix_finish();
|
||||||
|
@ -179,7 +194,7 @@ usage_sync() ->
|
||||||
"WARNING: This results in inconsistent configs among the clustered nodes."},
|
"WARNING: This results in inconsistent configs among the clustered nodes."},
|
||||||
{"conf cluster_sync fix",
|
{"conf cluster_sync fix",
|
||||||
"Sync the node with the most comprehensive configuration to other node.\n"
|
"Sync the node with the most comprehensive configuration to other node.\n"
|
||||||
"WARNING: typically the one with the highest tnxid."}
|
"WARNING: typically the config leader(with the highest tnxid)."}
|
||||||
].
|
].
|
||||||
|
|
||||||
status() ->
|
status() ->
|
||||||
|
@ -210,7 +225,8 @@ maybe_fix_inconsistent(Status, #{fix := Fix}) ->
|
||||||
emqx_ctl:print("Reset tnxid to 0 successfully~n");
|
emqx_ctl:print("Reset tnxid to 0 successfully~n");
|
||||||
inconsistent_tnx_id ->
|
inconsistent_tnx_id ->
|
||||||
print_tnx_id_status(Status),
|
print_tnx_id_status(Status),
|
||||||
emqx_ctl:print("run `./bin/emqx_ctl conf cluster_sync fix` when stuck for a long time");
|
Leader = emqx_cluster_rpc:find_leader(),
|
||||||
|
emqx_ctl:print(?SUGGESTION(Leader));
|
||||||
{inconsistent_key, TnxId, InconsistentKeys} ->
|
{inconsistent_key, TnxId, InconsistentKeys} ->
|
||||||
[{Target, _} | _] = AllConfs,
|
[{Target, _} | _] = AllConfs,
|
||||||
print_inconsistent_conf(InconsistentKeys, Target, Status, AllConfs),
|
print_inconsistent_conf(InconsistentKeys, Target, Status, AllConfs),
|
||||||
|
@ -223,7 +239,7 @@ maybe_fix_inconsistent(Status, #{fix := Fix}) ->
|
||||||
),
|
),
|
||||||
emqx_ctl:warning(
|
emqx_ctl:warning(
|
||||||
"Configuring different values (excluding node.name) through environment variables and etc/emqx.conf"
|
"Configuring different values (excluding node.name) through environment variables and etc/emqx.conf"
|
||||||
" is allowed but not recommended. "
|
" is allowed but not recommended.~n"
|
||||||
),
|
),
|
||||||
Fix andalso emqx_ctl:warning("So this fix will not make any changes.~n"),
|
Fix andalso emqx_ctl:warning("So this fix will not make any changes.~n"),
|
||||||
ok;
|
ok;
|
||||||
|
|
|
@ -148,7 +148,7 @@ t_commit_ok_but_apply_fail_on_other_node(_Config) ->
|
||||||
retry_times := 2,
|
retry_times := 2,
|
||||||
cluster_tnx_id := 2,
|
cluster_tnx_id := 2,
|
||||||
node_tnx_id := 1,
|
node_tnx_id := 1,
|
||||||
suggested := _
|
suggestion := _
|
||||||
}}},
|
}}},
|
||||||
Res1
|
Res1
|
||||||
),
|
),
|
||||||
|
|
|
@ -314,15 +314,15 @@ global_zone_configs(get, _Params, _Req) ->
|
||||||
{200, get_zones()};
|
{200, get_zones()};
|
||||||
global_zone_configs(put, #{body := Body}, _Req) ->
|
global_zone_configs(put, #{body := Body}, _Req) ->
|
||||||
PrevZones = get_zones(),
|
PrevZones = get_zones(),
|
||||||
Res =
|
{Res, Error} =
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(Path, Value, Acc) ->
|
fun(Path, Value, {Acc, Error}) ->
|
||||||
PrevValue = maps:get(Path, PrevZones),
|
PrevValue = maps:get(Path, PrevZones),
|
||||||
case Value =/= PrevValue of
|
case Value =/= PrevValue of
|
||||||
true ->
|
true ->
|
||||||
case emqx_conf:update([Path], Value, ?OPTS) of
|
case emqx_conf:update([Path], Value, ?OPTS) of
|
||||||
{ok, #{raw_config := RawConf}} ->
|
{ok, #{raw_config := RawConf}} ->
|
||||||
Acc#{Path => RawConf};
|
{Acc#{Path => RawConf}, Error};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?SLOG(error, #{
|
?SLOG(error, #{
|
||||||
msg => "update_global_zone_failed",
|
msg => "update_global_zone_failed",
|
||||||
|
@ -330,18 +330,18 @@ global_zone_configs(put, #{body := Body}, _Req) ->
|
||||||
path => Path,
|
path => Path,
|
||||||
value => Value
|
value => Value
|
||||||
}),
|
}),
|
||||||
Acc
|
{Acc, Error#{Path => Reason}}
|
||||||
end;
|
end;
|
||||||
false ->
|
false ->
|
||||||
Acc#{Path => Value}
|
{Acc#{Path => Value}, Error}
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
#{},
|
{#{}, #{}},
|
||||||
Body
|
Body
|
||||||
),
|
),
|
||||||
case maps:size(Res) =:= maps:size(Body) of
|
case maps:size(Res) =:= maps:size(Body) of
|
||||||
true -> {200, Res};
|
true -> {200, Res};
|
||||||
false -> {400, #{code => 'UPDATE_FAILED'}}
|
false -> {400, #{code => 'UPDATE_FAILED', message => ?ERR_MSG(Error)}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
config_reset(post, _Params, Req) ->
|
config_reset(post, _Params, Req) ->
|
||||||
|
|
Loading…
Reference in New Issue