feat(queue): clarify naming; identify shared subs by full topic filter
This commit is contained in:
parent
7e23f8d19f
commit
f213569460
|
@ -119,8 +119,8 @@ new(Opts) ->
|
||||||
{ok, emqx_persistent_session_ds_state:t(), t()}.
|
{ok, emqx_persistent_session_ds_state:t(), t()}.
|
||||||
open(S, Opts) ->
|
open(S, Opts) ->
|
||||||
SharedSubscriptions = fold_shared_subs(
|
SharedSubscriptions = fold_shared_subs(
|
||||||
fun(#share{} = TopicFilter, Sub, Acc) ->
|
fun(#share{} = ShareTopicFilter, Sub, Acc) ->
|
||||||
[{TopicFilter, to_agent_subscription(S, Sub)} | Acc]
|
[{ShareTopicFilter, to_agent_subscription(S, Sub)} | Acc]
|
||||||
end,
|
end,
|
||||||
[],
|
[],
|
||||||
S
|
S
|
||||||
|
@ -139,33 +139,33 @@ open(S, Opts) ->
|
||||||
emqx_types:subopts(),
|
emqx_types:subopts(),
|
||||||
emqx_persistent_session_ds:session()
|
emqx_persistent_session_ds:session()
|
||||||
) -> {ok, emqx_persistent_session_ds_state:t(), t()} | {error, emqx_types:reason_code()}.
|
) -> {ok, emqx_persistent_session_ds_state:t(), t()} | {error, emqx_types:reason_code()}.
|
||||||
on_subscribe(TopicFilter, SubOpts, #{s := S} = Session) ->
|
on_subscribe(#share{} = ShareTopicFilter, SubOpts, #{s := S} = Session) ->
|
||||||
Subscription = emqx_persistent_session_ds_state:get_subscription(TopicFilter, S),
|
Subscription = emqx_persistent_session_ds_state:get_subscription(ShareTopicFilter, S),
|
||||||
on_subscribe(Subscription, TopicFilter, SubOpts, Session).
|
on_subscribe(Subscription, ShareTopicFilter, SubOpts, Session).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% on_subscribe internal functions
|
%% on_subscribe internal functions
|
||||||
|
|
||||||
on_subscribe(undefined, TopicFilter, SubOpts, #{props := Props, s := S} = Session) ->
|
on_subscribe(undefined, ShareTopicFilter, SubOpts, #{props := Props, s := S} = Session) ->
|
||||||
#{max_subscriptions := MaxSubscriptions} = Props,
|
#{max_subscriptions := MaxSubscriptions} = Props,
|
||||||
case emqx_persistent_session_ds_state:n_subscriptions(S) < MaxSubscriptions of
|
case emqx_persistent_session_ds_state:n_subscriptions(S) < MaxSubscriptions of
|
||||||
true ->
|
true ->
|
||||||
create_new_subscription(TopicFilter, SubOpts, Session);
|
create_new_subscription(ShareTopicFilter, SubOpts, Session);
|
||||||
false ->
|
false ->
|
||||||
{error, ?RC_QUOTA_EXCEEDED}
|
{error, ?RC_QUOTA_EXCEEDED}
|
||||||
end;
|
end;
|
||||||
on_subscribe(Subscription, TopicFilter, SubOpts, Session) ->
|
on_subscribe(Subscription, ShareTopicFilter, SubOpts, Session) ->
|
||||||
update_subscription(Subscription, TopicFilter, SubOpts, Session).
|
update_subscription(Subscription, ShareTopicFilter, SubOpts, Session).
|
||||||
|
|
||||||
-dialyzer({nowarn_function, create_new_subscription/3}).
|
-dialyzer({nowarn_function, create_new_subscription/3}).
|
||||||
create_new_subscription(TopicFilter, SubOpts, #{
|
create_new_subscription(ShareTopicFilter, SubOpts, #{
|
||||||
s := S0,
|
s := S0,
|
||||||
shared_sub_s := #{agent := Agent} = SharedSubS0,
|
shared_sub_s := #{agent := Agent} = SharedSubS0,
|
||||||
props := Props
|
props := Props
|
||||||
}) ->
|
}) ->
|
||||||
case
|
case
|
||||||
emqx_persistent_session_ds_shared_subs_agent:can_subscribe(
|
emqx_persistent_session_ds_shared_subs_agent:can_subscribe(
|
||||||
Agent, TopicFilter, SubOpts
|
Agent, ShareTopicFilter, SubOpts
|
||||||
)
|
)
|
||||||
of
|
of
|
||||||
ok ->
|
ok ->
|
||||||
|
@ -184,17 +184,19 @@ create_new_subscription(TopicFilter, SubOpts, #{
|
||||||
start_time => now_ms()
|
start_time => now_ms()
|
||||||
},
|
},
|
||||||
S = emqx_persistent_session_ds_state:put_subscription(
|
S = emqx_persistent_session_ds_state:put_subscription(
|
||||||
TopicFilter, Subscription, S3
|
ShareTopicFilter, Subscription, S3
|
||||||
),
|
),
|
||||||
SharedSubS = schedule_subscribe(SharedSubS0, TopicFilter, SubOpts),
|
SharedSubS = schedule_subscribe(SharedSubS0, ShareTopicFilter, SubOpts),
|
||||||
{ok, S, SharedSubS};
|
{ok, S, SharedSubS};
|
||||||
{error, _} = Error ->
|
{error, _} = Error ->
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
update_subscription(#{current_state := SStateId0, id := SubId} = Sub0, TopicFilter, SubOpts, #{
|
update_subscription(
|
||||||
s := S0, shared_sub_s := SharedSubS, props := Props
|
#{current_state := SStateId0, id := SubId} = Sub0, ShareTopicFilter, SubOpts, #{
|
||||||
}) ->
|
s := S0, shared_sub_s := SharedSubS, props := Props
|
||||||
|
}
|
||||||
|
) ->
|
||||||
#{upgrade_qos := UpgradeQoS} = Props,
|
#{upgrade_qos := UpgradeQoS} = Props,
|
||||||
SState = #{parent_subscription => SubId, upgrade_qos => UpgradeQoS, subopts => SubOpts},
|
SState = #{parent_subscription => SubId, upgrade_qos => UpgradeQoS, subopts => SubOpts},
|
||||||
case emqx_persistent_session_ds_state:get_subscription_state(SStateId0, S0) of
|
case emqx_persistent_session_ds_state:get_subscription_state(SStateId0, S0) of
|
||||||
|
@ -208,31 +210,33 @@ update_subscription(#{current_state := SStateId0, id := SubId} = Sub0, TopicFilt
|
||||||
SStateId, SState, S1
|
SStateId, SState, S1
|
||||||
),
|
),
|
||||||
Sub = Sub0#{current_state => SStateId},
|
Sub = Sub0#{current_state => SStateId},
|
||||||
S = emqx_persistent_session_ds_state:put_subscription(TopicFilter, Sub, S2),
|
S = emqx_persistent_session_ds_state:put_subscription(ShareTopicFilter, Sub, S2),
|
||||||
{ok, S, SharedSubS}
|
{ok, S, SharedSubS}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-dialyzer({nowarn_function, schedule_subscribe/3}).
|
-dialyzer({nowarn_function, schedule_subscribe/3}).
|
||||||
schedule_subscribe(
|
schedule_subscribe(
|
||||||
#{agent := Agent0, scheduled_actions := ScheduledActions0} = SharedSubS0, TopicFilter, SubOpts
|
#{agent := Agent0, scheduled_actions := ScheduledActions0} = SharedSubS0,
|
||||||
|
ShareTopicFilter,
|
||||||
|
SubOpts
|
||||||
) ->
|
) ->
|
||||||
case ScheduledActions0 of
|
case ScheduledActions0 of
|
||||||
#{TopicFilter := ScheduledAction} ->
|
#{ShareTopicFilter := ScheduledAction} ->
|
||||||
ScheduledActions1 = ScheduledActions0#{
|
ScheduledActions1 = ScheduledActions0#{
|
||||||
TopicFilter => ScheduledAction#{type => {?schedule_subscribe, SubOpts}}
|
ShareTopicFilter => ScheduledAction#{type => {?schedule_subscribe, SubOpts}}
|
||||||
},
|
},
|
||||||
?tp(warning, shared_subs_schedule_subscribe_override, #{
|
?tp(warning, shared_subs_schedule_subscribe_override, #{
|
||||||
topic_filter => TopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
new_type => {?schedule_subscribe, SubOpts},
|
new_type => {?schedule_subscribe, SubOpts},
|
||||||
old_action => format_schedule_action(ScheduledAction)
|
old_action => format_schedule_action(ScheduledAction)
|
||||||
}),
|
}),
|
||||||
SharedSubS0#{scheduled_actions := ScheduledActions1};
|
SharedSubS0#{scheduled_actions := ScheduledActions1};
|
||||||
_ ->
|
_ ->
|
||||||
?tp(warning, shared_subs_schedule_subscribe_new, #{
|
?tp(warning, shared_subs_schedule_subscribe_new, #{
|
||||||
topic_filter => TopicFilter, subopts => SubOpts
|
share_topic_filter => ShareTopicFilter, subopts => SubOpts
|
||||||
}),
|
}),
|
||||||
Agent1 = emqx_persistent_session_ds_shared_subs_agent:on_subscribe(
|
Agent1 = emqx_persistent_session_ds_shared_subs_agent:on_subscribe(
|
||||||
Agent0, TopicFilter, SubOpts
|
Agent0, ShareTopicFilter, SubOpts
|
||||||
),
|
),
|
||||||
SharedSubS0#{agent => Agent1}
|
SharedSubS0#{agent => Agent1}
|
||||||
end.
|
end.
|
||||||
|
@ -242,22 +246,22 @@ schedule_subscribe(
|
||||||
|
|
||||||
-spec on_unsubscribe(
|
-spec on_unsubscribe(
|
||||||
emqx_persistent_session_ds:id(),
|
emqx_persistent_session_ds:id(),
|
||||||
emqx_persistent_session_ds:topic_filter(),
|
share_topic_filter(),
|
||||||
emqx_persistent_session_ds_state:t(),
|
emqx_persistent_session_ds_state:t(),
|
||||||
t()
|
t()
|
||||||
) ->
|
) ->
|
||||||
{ok, emqx_persistent_session_ds_state:t(), t(), emqx_persistent_session_ds:subscription()}
|
{ok, emqx_persistent_session_ds_state:t(), t(), emqx_persistent_session_ds:subscription()}
|
||||||
| {error, emqx_types:reason_code()}.
|
| {error, emqx_types:reason_code()}.
|
||||||
on_unsubscribe(SessionId, TopicFilter, S0, SharedSubS0) ->
|
on_unsubscribe(SessionId, ShareTopicFilter, S0, SharedSubS0) ->
|
||||||
case lookup(TopicFilter, S0) of
|
case lookup(ShareTopicFilter, S0) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{error, ?RC_NO_SUBSCRIPTION_EXISTED};
|
{error, ?RC_NO_SUBSCRIPTION_EXISTED};
|
||||||
#{id := SubId} = Subscription ->
|
#{id := SubId} = Subscription ->
|
||||||
?tp(persistent_session_ds_subscription_delete, #{
|
?tp(persistent_session_ds_subscription_delete, #{
|
||||||
session_id => SessionId, topic_filter => TopicFilter
|
session_id => SessionId, share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
S = emqx_persistent_session_ds_state:del_subscription(TopicFilter, S0),
|
S = emqx_persistent_session_ds_state:del_subscription(ShareTopicFilter, S0),
|
||||||
SharedSubS = schedule_unsubscribe(S, SharedSubS0, SubId, TopicFilter),
|
SharedSubS = schedule_unsubscribe(S, SharedSubS0, SubId, ShareTopicFilter),
|
||||||
{ok, S, SharedSubS, Subscription}
|
{ok, S, SharedSubS, Subscription}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -265,16 +269,16 @@ on_unsubscribe(SessionId, TopicFilter, S0, SharedSubS0) ->
|
||||||
%% on_unsubscribe internal functions
|
%% on_unsubscribe internal functions
|
||||||
|
|
||||||
schedule_unsubscribe(
|
schedule_unsubscribe(
|
||||||
S, #{scheduled_actions := ScheduledActions0} = SharedSubS0, UnsubscridedSubId, TopicFilter
|
S, #{scheduled_actions := ScheduledActions0} = SharedSubS0, UnsubscridedSubId, ShareTopicFilter
|
||||||
) ->
|
) ->
|
||||||
case ScheduledActions0 of
|
case ScheduledActions0 of
|
||||||
#{TopicFilter := ScheduledAction0} ->
|
#{ShareTopicFilter := ScheduledAction0} ->
|
||||||
ScheduledAction1 = ScheduledAction0#{type => ?schedule_unsubscribe},
|
ScheduledAction1 = ScheduledAction0#{type => ?schedule_unsubscribe},
|
||||||
ScheduledActions1 = ScheduledActions0#{
|
ScheduledActions1 = ScheduledActions0#{
|
||||||
TopicFilter => ScheduledAction1
|
ShareTopicFilter => ScheduledAction1
|
||||||
},
|
},
|
||||||
?tp(warning, shared_subs_schedule_unsubscribe_override, #{
|
?tp(warning, shared_subs_schedule_unsubscribe_override, #{
|
||||||
topic_filter => TopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
new_type => ?schedule_unsubscribe,
|
new_type => ?schedule_unsubscribe,
|
||||||
old_action => format_schedule_action(ScheduledAction0)
|
old_action => format_schedule_action(ScheduledAction0)
|
||||||
}),
|
}),
|
||||||
|
@ -282,14 +286,14 @@ schedule_unsubscribe(
|
||||||
_ ->
|
_ ->
|
||||||
StreamKeys = stream_keys_by_sub_id(S, UnsubscridedSubId),
|
StreamKeys = stream_keys_by_sub_id(S, UnsubscridedSubId),
|
||||||
ScheduledActions1 = ScheduledActions0#{
|
ScheduledActions1 = ScheduledActions0#{
|
||||||
TopicFilter => #{
|
ShareTopicFilter => #{
|
||||||
type => ?schedule_unsubscribe,
|
type => ?schedule_unsubscribe,
|
||||||
stream_keys_to_wait => StreamKeys,
|
stream_keys_to_wait => StreamKeys,
|
||||||
progresses => []
|
progresses => []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
?tp(warning, shared_subs_schedule_unsubscribe_new, #{
|
?tp(warning, shared_subs_schedule_unsubscribe_new, #{
|
||||||
topic_filter => TopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
stream_keys => format_stream_keys(StreamKeys)
|
stream_keys => format_stream_keys(StreamKeys)
|
||||||
}),
|
}),
|
||||||
SharedSubS0#{scheduled_actions := ScheduledActions1}
|
SharedSubS0#{scheduled_actions := ScheduledActions1}
|
||||||
|
@ -322,13 +326,13 @@ renew_streams(S0, #{agent := Agent0, scheduled_actions := ScheduledActions} = Sh
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% renew_streams internal functions
|
%% renew_streams internal functions
|
||||||
|
|
||||||
accept_stream(#{topic_filter := TopicFilter} = Event, S, ScheduledActions) ->
|
accept_stream(#{share_topic_filter := ShareTopicFilter} = Event, S, ScheduledActions) ->
|
||||||
%% If we have a pending action (subscribe or unsubscribe) for this topic filter,
|
%% If we have a pending action (subscribe or unsubscribe) for this topic filter,
|
||||||
%% we should not accept a stream and start replaying it. We won't use it anyway:
|
%% we should not accept a stream and start replaying it. We won't use it anyway:
|
||||||
%% * if subscribe is pending, we will reset agent obtain a new lease
|
%% * if subscribe is pending, we will reset agent obtain a new lease
|
||||||
%% * if unsubscribe is pending, we will drop connection
|
%% * if unsubscribe is pending, we will drop connection
|
||||||
case ScheduledActions of
|
case ScheduledActions of
|
||||||
#{TopicFilter := _Action} ->
|
#{ShareTopicFilter := _Action} ->
|
||||||
S;
|
S;
|
||||||
_ ->
|
_ ->
|
||||||
accept_stream(Event, S)
|
accept_stream(Event, S)
|
||||||
|
@ -336,13 +340,13 @@ accept_stream(#{topic_filter := TopicFilter} = Event, S, ScheduledActions) ->
|
||||||
|
|
||||||
accept_stream(
|
accept_stream(
|
||||||
#{
|
#{
|
||||||
topic_filter := TopicFilter,
|
share_topic_filter := ShareTopicFilter,
|
||||||
stream := Stream,
|
stream := Stream,
|
||||||
progress := #{iterator := Iterator} = _Progress
|
progress := #{iterator := Iterator} = _Progress
|
||||||
} = _Event,
|
} = _Event,
|
||||||
S0
|
S0
|
||||||
) ->
|
) ->
|
||||||
case emqx_persistent_session_ds_state:get_subscription(TopicFilter, S0) of
|
case emqx_persistent_session_ds_state:get_subscription(ShareTopicFilter, S0) of
|
||||||
undefined ->
|
undefined ->
|
||||||
%% We unsubscribed
|
%% We unsubscribed
|
||||||
S0;
|
S0;
|
||||||
|
@ -375,9 +379,9 @@ accept_stream(
|
||||||
end.
|
end.
|
||||||
|
|
||||||
revoke_stream(
|
revoke_stream(
|
||||||
#{topic_filter := TopicFilter, stream := Stream}, S0
|
#{share_topic_filter := ShareTopicFilter, stream := Stream}, S0
|
||||||
) ->
|
) ->
|
||||||
case emqx_persistent_session_ds_state:get_subscription(TopicFilter, S0) of
|
case emqx_persistent_session_ds_state:get_subscription(ShareTopicFilter, S0) of
|
||||||
undefined ->
|
undefined ->
|
||||||
%% This should not happen.
|
%% This should not happen.
|
||||||
%% Agent should have received unsubscribe callback
|
%% Agent should have received unsubscribe callback
|
||||||
|
@ -427,12 +431,7 @@ all_stream_progresses(S, _Agent, NeedUnacked) ->
|
||||||
CommQos1 = emqx_persistent_session_ds_state:get_seqno(?committed(?QOS_1), S),
|
CommQos1 = emqx_persistent_session_ds_state:get_seqno(?committed(?QOS_1), S),
|
||||||
CommQos2 = emqx_persistent_session_ds_state:get_seqno(?committed(?QOS_2), S),
|
CommQos2 = emqx_persistent_session_ds_state:get_seqno(?committed(?QOS_2), S),
|
||||||
fold_shared_stream_states(
|
fold_shared_stream_states(
|
||||||
fun(
|
fun(ShareTopicFilter, Stream, SRS, ProgressesAcc0) ->
|
||||||
#share{group = Group},
|
|
||||||
Stream,
|
|
||||||
SRS,
|
|
||||||
ProgressesAcc0
|
|
||||||
) ->
|
|
||||||
case
|
case
|
||||||
is_stream_started(CommQos1, CommQos2, SRS) and
|
is_stream_started(CommQos1, CommQos2, SRS) and
|
||||||
(NeedUnacked or is_stream_fully_acked(CommQos1, CommQos2, SRS))
|
(NeedUnacked or is_stream_fully_acked(CommQos1, CommQos2, SRS))
|
||||||
|
@ -440,7 +439,7 @@ all_stream_progresses(S, _Agent, NeedUnacked) ->
|
||||||
true ->
|
true ->
|
||||||
StreamProgress = stream_progress(CommQos1, CommQos2, Stream, SRS),
|
StreamProgress = stream_progress(CommQos1, CommQos2, Stream, SRS),
|
||||||
maps:update_with(
|
maps:update_with(
|
||||||
Group,
|
ShareTopicFilter,
|
||||||
fun(Progresses) -> [StreamProgress | Progresses] end,
|
fun(Progresses) -> [StreamProgress | Progresses] end,
|
||||||
[StreamProgress],
|
[StreamProgress],
|
||||||
ProgressesAcc0
|
ProgressesAcc0
|
||||||
|
@ -455,12 +454,12 @@ all_stream_progresses(S, _Agent, NeedUnacked) ->
|
||||||
|
|
||||||
run_scheduled_actions(S, Agent, ScheduledActions) ->
|
run_scheduled_actions(S, Agent, ScheduledActions) ->
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(TopicFilter, Action0, {AgentAcc0, ScheduledActionsAcc}) ->
|
fun(ShareTopicFilter, Action0, {AgentAcc0, ScheduledActionsAcc}) ->
|
||||||
case run_scheduled_action(S, AgentAcc0, TopicFilter, Action0) of
|
case run_scheduled_action(S, AgentAcc0, ShareTopicFilter, Action0) of
|
||||||
{ok, AgentAcc1} ->
|
{ok, AgentAcc1} ->
|
||||||
{AgentAcc1, maps:remove(TopicFilter, ScheduledActionsAcc)};
|
{AgentAcc1, maps:remove(ShareTopicFilter, ScheduledActionsAcc)};
|
||||||
{continue, Action1} ->
|
{continue, Action1} ->
|
||||||
{AgentAcc0, ScheduledActionsAcc#{TopicFilter => Action1}}
|
{AgentAcc0, ScheduledActionsAcc#{ShareTopicFilter => Action1}}
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
{Agent, ScheduledActions},
|
{Agent, ScheduledActions},
|
||||||
|
@ -470,7 +469,7 @@ run_scheduled_actions(S, Agent, ScheduledActions) ->
|
||||||
run_scheduled_action(
|
run_scheduled_action(
|
||||||
S,
|
S,
|
||||||
Agent0,
|
Agent0,
|
||||||
#share{group = Group} = TopicFilter,
|
ShareTopicFilter,
|
||||||
#{type := Type, stream_keys_to_wait := StreamKeysToWait0, progresses := Progresses0} = Action
|
#{type := Type, stream_keys_to_wait := StreamKeysToWait0, progresses := Progresses0} = Action
|
||||||
) ->
|
) ->
|
||||||
StreamKeysToWait1 = filter_unfinished_streams(S, StreamKeysToWait0),
|
StreamKeysToWait1 = filter_unfinished_streams(S, StreamKeysToWait0),
|
||||||
|
@ -478,31 +477,31 @@ run_scheduled_action(
|
||||||
case StreamKeysToWait1 of
|
case StreamKeysToWait1 of
|
||||||
[] ->
|
[] ->
|
||||||
?tp(warning, shared_subs_schedule_action_complete, #{
|
?tp(warning, shared_subs_schedule_action_complete, #{
|
||||||
topic_filter => TopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
progresses => format_stream_progresses(Progresses1),
|
progresses => format_stream_progresses(Progresses1),
|
||||||
type => Type
|
type => Type
|
||||||
}),
|
}),
|
||||||
%% Regular progress won't se unsubscribed streams, so we need to
|
%% Regular progress won't se unsubscribed streams, so we need to
|
||||||
%% send the progress explicitly.
|
%% send the progress explicitly.
|
||||||
Agent1 = emqx_persistent_session_ds_shared_subs_agent:on_stream_progress(
|
Agent1 = emqx_persistent_session_ds_shared_subs_agent:on_stream_progress(
|
||||||
Agent0, #{Group => Progresses1}
|
Agent0, #{ShareTopicFilter => Progresses1}
|
||||||
),
|
),
|
||||||
case Type of
|
case Type of
|
||||||
{?schedule_subscribe, SubOpts} ->
|
{?schedule_subscribe, SubOpts} ->
|
||||||
{ok,
|
{ok,
|
||||||
emqx_persistent_session_ds_shared_subs_agent:on_subscribe(
|
emqx_persistent_session_ds_shared_subs_agent:on_subscribe(
|
||||||
Agent1, TopicFilter, SubOpts
|
Agent1, ShareTopicFilter, SubOpts
|
||||||
)};
|
)};
|
||||||
?schedule_unsubscribe ->
|
?schedule_unsubscribe ->
|
||||||
{ok,
|
{ok,
|
||||||
emqx_persistent_session_ds_shared_subs_agent:on_unsubscribe(
|
emqx_persistent_session_ds_shared_subs_agent:on_unsubscribe(
|
||||||
Agent1, TopicFilter, Progresses1
|
Agent1, ShareTopicFilter, Progresses1
|
||||||
)}
|
)}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Action1 = Action#{stream_keys_to_wait => StreamKeysToWait1, progresses => Progresses1},
|
Action1 = Action#{stream_keys_to_wait => StreamKeysToWait1, progresses => Progresses1},
|
||||||
?tp(warning, shared_subs_schedule_action_continue, #{
|
?tp(warning, shared_subs_schedule_action_continue, #{
|
||||||
topic_filter => TopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
new_action => format_schedule_action(Action1)
|
new_action => format_schedule_action(Action1)
|
||||||
}),
|
}),
|
||||||
{continue, Action1}
|
{continue, Action1}
|
||||||
|
@ -551,8 +550,8 @@ on_disconnect(S0, #{agent := Agent0} = SharedSubS0) ->
|
||||||
|
|
||||||
revoke_all_streams(S0) ->
|
revoke_all_streams(S0) ->
|
||||||
fold_shared_stream_states(
|
fold_shared_stream_states(
|
||||||
fun(TopicFilter, Stream, _SRS, S) ->
|
fun(ShareTopicFilter, Stream, _SRS, S) ->
|
||||||
revoke_stream(#{topic_filter => TopicFilter, stream => Stream}, S)
|
revoke_stream(#{share_topic_filter => ShareTopicFilter, stream => Stream}, S)
|
||||||
end,
|
end,
|
||||||
S0,
|
S0,
|
||||||
S0
|
S0
|
||||||
|
@ -580,8 +579,8 @@ to_map(_S, _SharedSubS) ->
|
||||||
%% Generic helpers
|
%% Generic helpers
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
lookup(TopicFilter, S) ->
|
lookup(ShareTopicFilter, S) ->
|
||||||
case emqx_persistent_session_ds_state:get_subscription(TopicFilter, S) of
|
case emqx_persistent_session_ds_state:get_subscription(ShareTopicFilter, S) of
|
||||||
Sub = #{current_state := SStateId} ->
|
Sub = #{current_state := SStateId} ->
|
||||||
case emqx_persistent_session_ds_state:get_subscription_state(SStateId, S) of
|
case emqx_persistent_session_ds_state:get_subscription_state(SStateId, S) of
|
||||||
#{subopts := SubOpts} ->
|
#{subopts := SubOpts} ->
|
||||||
|
@ -640,7 +639,7 @@ stream_progress(
|
||||||
fold_shared_subs(Fun, Acc, S) ->
|
fold_shared_subs(Fun, Acc, S) ->
|
||||||
emqx_persistent_session_ds_state:fold_subscriptions(
|
emqx_persistent_session_ds_state:fold_subscriptions(
|
||||||
fun
|
fun
|
||||||
(#share{} = TopicFilter, Sub, Acc0) -> Fun(TopicFilter, Sub, Acc0);
|
(#share{} = ShareTopicFilter, Sub, Acc0) -> Fun(ShareTopicFilter, Sub, Acc0);
|
||||||
(_, _Sub, Acc0) -> Acc0
|
(_, _Sub, Acc0) -> Acc0
|
||||||
end,
|
end,
|
||||||
Acc,
|
Acc,
|
||||||
|
@ -650,10 +649,10 @@ fold_shared_subs(Fun, Acc, S) ->
|
||||||
fold_shared_stream_states(Fun, Acc, S) ->
|
fold_shared_stream_states(Fun, Acc, S) ->
|
||||||
%% TODO
|
%% TODO
|
||||||
%% Optimize or cache
|
%% Optimize or cache
|
||||||
TopicFilters = fold_shared_subs(
|
ShareTopicFilters = fold_shared_subs(
|
||||||
fun
|
fun
|
||||||
(#share{} = TopicFilter, #{id := Id} = _Sub, Acc0) ->
|
(#share{} = ShareTopicFilter, #{id := Id} = _Sub, Acc0) ->
|
||||||
Acc0#{Id => TopicFilter};
|
Acc0#{Id => ShareTopicFilter};
|
||||||
(_, _, Acc0) ->
|
(_, _, Acc0) ->
|
||||||
Acc0
|
Acc0
|
||||||
end,
|
end,
|
||||||
|
@ -662,9 +661,9 @@ fold_shared_stream_states(Fun, Acc, S) ->
|
||||||
),
|
),
|
||||||
emqx_persistent_session_ds_state:fold_streams(
|
emqx_persistent_session_ds_state:fold_streams(
|
||||||
fun({SubId, Stream}, SRS, Acc0) ->
|
fun({SubId, Stream}, SRS, Acc0) ->
|
||||||
case TopicFilters of
|
case ShareTopicFilters of
|
||||||
#{SubId := TopicFilter} ->
|
#{SubId := ShareTopicFilter} ->
|
||||||
Fun(TopicFilter, Stream, SRS, Acc0);
|
Fun(ShareTopicFilter, Stream, SRS, Acc0);
|
||||||
_ ->
|
_ ->
|
||||||
Acc0
|
Acc0
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-type t() :: term().
|
-type t() :: term().
|
||||||
-type topic_filter() :: emqx_persistent_session_ds:share_topic_filter().
|
-type share_topic_filter() :: emqx_persistent_session_ds:share_topic_filter().
|
||||||
|
|
||||||
-type opts() :: #{
|
-type opts() :: #{
|
||||||
session_id := session_id()
|
session_id := session_id()
|
||||||
|
@ -28,21 +28,21 @@
|
||||||
-type stream_lease() :: #{
|
-type stream_lease() :: #{
|
||||||
type => lease,
|
type => lease,
|
||||||
%% Used as "external" subscription_id
|
%% Used as "external" subscription_id
|
||||||
topic_filter := topic_filter(),
|
share_topic_filter := share_topic_filter(),
|
||||||
stream := emqx_ds:stream(),
|
stream := emqx_ds:stream(),
|
||||||
iterator := emqx_ds:iterator()
|
iterator := emqx_ds:iterator()
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-type stream_revoke() :: #{
|
-type stream_revoke() :: #{
|
||||||
type => revoke,
|
type => revoke,
|
||||||
topic_filter := topic_filter(),
|
share_topic_filter := share_topic_filter(),
|
||||||
stream := emqx_ds:stream()
|
stream := emqx_ds:stream()
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-type stream_lease_event() :: stream_lease() | stream_revoke().
|
-type stream_lease_event() :: stream_lease() | stream_revoke().
|
||||||
|
|
||||||
-type stream_progress() :: #{
|
-type stream_progress() :: #{
|
||||||
topic_filter := topic_filter(),
|
share_topic_filter := share_topic_filter(),
|
||||||
stream := emqx_ds:stream(),
|
stream := emqx_ds:stream(),
|
||||||
iterator := emqx_ds:iterator(),
|
iterator := emqx_ds:iterator(),
|
||||||
use_finished := boolean()
|
use_finished := boolean()
|
||||||
|
@ -80,13 +80,13 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-callback new(opts()) -> t().
|
-callback new(opts()) -> t().
|
||||||
-callback open([{topic_filter(), subscription()}], opts()) -> t().
|
-callback open([{share_topic_filter(), subscription()}], opts()) -> t().
|
||||||
-callback can_subscribe(t(), topic_filter(), emqx_types:subopts()) -> ok | {error, term()}.
|
-callback can_subscribe(t(), share_topic_filter(), emqx_types:subopts()) -> ok | {error, term()}.
|
||||||
-callback on_subscribe(t(), topic_filter(), emqx_types:subopts()) -> t().
|
-callback on_subscribe(t(), share_topic_filter(), emqx_types:subopts()) -> t().
|
||||||
-callback on_unsubscribe(t(), topic_filter(), [stream_progress()]) -> t().
|
-callback on_unsubscribe(t(), share_topic_filter(), [stream_progress()]) -> t().
|
||||||
-callback on_disconnect(t(), #{emqx_types:group() => [stream_progress()]}) -> t().
|
-callback on_disconnect(t(), #{share_topic_filter() => [stream_progress()]}) -> t().
|
||||||
-callback renew_streams(t()) -> {[stream_lease_event()], t()}.
|
-callback renew_streams(t()) -> {[stream_lease_event()], t()}.
|
||||||
-callback on_stream_progress(t(), #{emqx_types:group() => [stream_progress()]}) -> t().
|
-callback on_stream_progress(t(), #{share_topic_filter() => [stream_progress()]}) -> t().
|
||||||
-callback on_info(t(), term()) -> t().
|
-callback on_info(t(), term()) -> t().
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -97,23 +97,23 @@
|
||||||
new(Opts) ->
|
new(Opts) ->
|
||||||
?shared_subs_agent:new(Opts).
|
?shared_subs_agent:new(Opts).
|
||||||
|
|
||||||
-spec open([{topic_filter(), subscription()}], opts()) -> t().
|
-spec open([{share_topic_filter(), subscription()}], opts()) -> t().
|
||||||
open(Topics, Opts) ->
|
open(Topics, Opts) ->
|
||||||
?shared_subs_agent:open(Topics, Opts).
|
?shared_subs_agent:open(Topics, Opts).
|
||||||
|
|
||||||
-spec can_subscribe(t(), topic_filter(), emqx_types:subopts()) -> ok | {error, term()}.
|
-spec can_subscribe(t(), share_topic_filter(), emqx_types:subopts()) -> ok | {error, term()}.
|
||||||
can_subscribe(Agent, TopicFilter, SubOpts) ->
|
can_subscribe(Agent, ShareTopicFilter, SubOpts) ->
|
||||||
?shared_subs_agent:can_subscribe(Agent, TopicFilter, SubOpts).
|
?shared_subs_agent:can_subscribe(Agent, ShareTopicFilter, SubOpts).
|
||||||
|
|
||||||
-spec on_subscribe(t(), topic_filter(), emqx_types:subopts()) -> t().
|
-spec on_subscribe(t(), share_topic_filter(), emqx_types:subopts()) -> t().
|
||||||
on_subscribe(Agent, TopicFilter, SubOpts) ->
|
on_subscribe(Agent, ShareTopicFilter, SubOpts) ->
|
||||||
?shared_subs_agent:on_subscribe(Agent, TopicFilter, SubOpts).
|
?shared_subs_agent:on_subscribe(Agent, ShareTopicFilter, SubOpts).
|
||||||
|
|
||||||
-spec on_unsubscribe(t(), topic_filter(), [stream_progress()]) -> t().
|
-spec on_unsubscribe(t(), share_topic_filter(), [stream_progress()]) -> t().
|
||||||
on_unsubscribe(Agent, TopicFilter, StreamProgresses) ->
|
on_unsubscribe(Agent, ShareTopicFilter, StreamProgresses) ->
|
||||||
?shared_subs_agent:on_unsubscribe(Agent, TopicFilter, StreamProgresses).
|
?shared_subs_agent:on_unsubscribe(Agent, ShareTopicFilter, StreamProgresses).
|
||||||
|
|
||||||
-spec on_disconnect(t(), #{emqx_types:group() => [stream_progress()]}) -> t().
|
-spec on_disconnect(t(), #{share_topic_filter() => [stream_progress()]}) -> t().
|
||||||
on_disconnect(Agent, StreamProgresses) ->
|
on_disconnect(Agent, StreamProgresses) ->
|
||||||
?shared_subs_agent:on_disconnect(Agent, StreamProgresses).
|
?shared_subs_agent:on_disconnect(Agent, StreamProgresses).
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ on_disconnect(Agent, StreamProgresses) ->
|
||||||
renew_streams(Agent) ->
|
renew_streams(Agent) ->
|
||||||
?shared_subs_agent:renew_streams(Agent).
|
?shared_subs_agent:renew_streams(Agent).
|
||||||
|
|
||||||
-spec on_stream_progress(t(), #{emqx_types:group() => [stream_progress()]}) -> t().
|
-spec on_stream_progress(t(), #{share_topic_filter() => [stream_progress()]}) -> t().
|
||||||
on_stream_progress(Agent, StreamProgress) ->
|
on_stream_progress(Agent, StreamProgress) ->
|
||||||
?shared_subs_agent:on_stream_progress(Agent, StreamProgress).
|
?shared_subs_agent:on_stream_progress(Agent, StreamProgress).
|
||||||
|
|
||||||
|
|
|
@ -26,18 +26,66 @@
|
||||||
|
|
||||||
-behaviour(emqx_persistent_session_ds_shared_subs_agent).
|
-behaviour(emqx_persistent_session_ds_shared_subs_agent).
|
||||||
|
|
||||||
|
-type share_topic_filter() :: emqx_persistent_session_ds:share_topic_filter().
|
||||||
|
-type group_id() :: share_topic_filter().
|
||||||
|
|
||||||
|
-type progress() :: emqx_persistent_session_ds_shared_subs:progress().
|
||||||
|
-type external_lease_event() ::
|
||||||
|
#{
|
||||||
|
type => lease,
|
||||||
|
stream => emqx_ds:stream(),
|
||||||
|
progress => progress(),
|
||||||
|
share_topic_filter => emqx_persistent_session_ds:share_topic_filter()
|
||||||
|
}
|
||||||
|
| #{
|
||||||
|
type => revoke,
|
||||||
|
stream => emqx_ds:stream(),
|
||||||
|
share_topic_filter => emqx_persistent_session_ds:share_topic_filter()
|
||||||
|
}.
|
||||||
|
|
||||||
|
-type options() :: #{
|
||||||
|
session_id := emqx_persistent_session_ds:id()
|
||||||
|
}.
|
||||||
|
|
||||||
|
-type t() :: #{
|
||||||
|
groups := #{
|
||||||
|
group_id() => emqx_ds_shared_sub_group_sm:t()
|
||||||
|
},
|
||||||
|
session_id := emqx_persistent_session_ds:id()
|
||||||
|
}.
|
||||||
|
|
||||||
|
%% Techinically, group_id and share_topic_filter are the same.
|
||||||
|
%% However, we speak in the terms of share_topic_filter in the API,
|
||||||
|
%% which is known to the shared subscription handler of persistent session.
|
||||||
|
%%
|
||||||
|
%% And we speak in the terms of group_id internally:
|
||||||
|
%% * we keep group_sm's in the state by group_id
|
||||||
|
%% * we use group_id to address group_sm's, e.g. when sending messages to them
|
||||||
|
%% from leader or from themselves.
|
||||||
|
-define(group_id(ShareTopicFilter), ShareTopicFilter).
|
||||||
|
-define(share_topic_filter(GroupId), GroupId).
|
||||||
|
|
||||||
-record(message_to_group_sm, {
|
-record(message_to_group_sm, {
|
||||||
group :: emqx_types:group(),
|
group_id :: group_id(),
|
||||||
message :: term()
|
message :: term()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
-export_type([
|
||||||
|
t/0,
|
||||||
|
group_id/0,
|
||||||
|
options/0,
|
||||||
|
external_lease_event/0
|
||||||
|
]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% API
|
%% API
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-spec new(options()) -> t().
|
||||||
new(Opts) ->
|
new(Opts) ->
|
||||||
init_state(Opts).
|
init_state(Opts).
|
||||||
|
|
||||||
|
-spec open([{share_topic_filter(), emqx_types:subopts()}], options()) -> t().
|
||||||
open(TopicSubscriptions, Opts) ->
|
open(TopicSubscriptions, Opts) ->
|
||||||
State0 = init_state(Opts),
|
State0 = init_state(Opts),
|
||||||
State1 = lists:foldl(
|
State1 = lists:foldl(
|
||||||
|
@ -45,32 +93,41 @@ open(TopicSubscriptions, Opts) ->
|
||||||
?tp(warning, ds_agent_open_subscription, #{
|
?tp(warning, ds_agent_open_subscription, #{
|
||||||
topic_filter => ShareTopicFilter
|
topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
add_group_subscription(State, ShareTopicFilter)
|
add_shared_subscription(State, ShareTopicFilter)
|
||||||
end,
|
end,
|
||||||
State0,
|
State0,
|
||||||
TopicSubscriptions
|
TopicSubscriptions
|
||||||
),
|
),
|
||||||
State1.
|
State1.
|
||||||
|
|
||||||
can_subscribe(_State, _TopicFilter, _SubOpts) ->
|
-spec can_subscribe(t(), share_topic_filter(), emqx_types:subopts()) -> ok.
|
||||||
|
can_subscribe(_State, _ShareTopicFilter, _SubOpts) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
on_subscribe(State0, TopicFilter, _SubOpts) ->
|
-spec on_subscribe(t(), share_topic_filter(), emqx_types:subopts()) -> t().
|
||||||
|
on_subscribe(State0, ShareTopicFilter, _SubOpts) ->
|
||||||
?tp(warning, ds_agent_on_subscribe, #{
|
?tp(warning, ds_agent_on_subscribe, #{
|
||||||
topic_filter => TopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
add_group_subscription(State0, TopicFilter).
|
add_shared_subscription(State0, ShareTopicFilter).
|
||||||
|
|
||||||
on_unsubscribe(State, TopicFilter, GroupProgress) ->
|
-spec on_unsubscribe(t(), share_topic_filter(), [
|
||||||
delete_group_subscription(State, TopicFilter, GroupProgress).
|
emqx_persistent_session_ds_shared_subs:agent_stream_progress()
|
||||||
|
]) -> t().
|
||||||
|
on_unsubscribe(State, ShareTopicFilter, GroupProgress) ->
|
||||||
|
delete_shared_subscription(State, ShareTopicFilter, GroupProgress).
|
||||||
|
|
||||||
|
-spec renew_streams(t()) -> {[emqx_persistent_session_ds_shared_subs:agent_stream_event()], t()}.
|
||||||
renew_streams(#{} = State) ->
|
renew_streams(#{} = State) ->
|
||||||
fetch_stream_events(State).
|
fetch_stream_events(State).
|
||||||
|
|
||||||
|
-spec on_stream_progress(t(), #{
|
||||||
|
share_topic_filter() => [emqx_persistent_session_ds_shared_subs:agent_stream_progress()]
|
||||||
|
}) -> t().
|
||||||
on_stream_progress(State, StreamProgresses) ->
|
on_stream_progress(State, StreamProgresses) ->
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(Group, GroupProgresses, StateAcc) ->
|
fun(ShareTopicFilter, GroupProgresses, StateAcc) ->
|
||||||
with_group_sm(StateAcc, Group, fun(GSM) ->
|
with_group_sm(StateAcc, ?group_id(ShareTopicFilter), fun(GSM) ->
|
||||||
emqx_ds_shared_sub_group_sm:handle_stream_progress(GSM, GroupProgresses)
|
emqx_ds_shared_sub_group_sm:handle_stream_progress(GSM, GroupProgresses)
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
|
@ -78,72 +135,74 @@ on_stream_progress(State, StreamProgresses) ->
|
||||||
StreamProgresses
|
StreamProgresses
|
||||||
).
|
).
|
||||||
|
|
||||||
|
-spec on_disconnect(t(), [emqx_persistent_session_ds_shared_subs:agent_stream_progress()]) -> t().
|
||||||
on_disconnect(#{groups := Groups0} = State, StreamProgresses) ->
|
on_disconnect(#{groups := Groups0} = State, StreamProgresses) ->
|
||||||
ok = maps:foreach(
|
ok = maps:foreach(
|
||||||
fun(Group, GroupSM0) ->
|
fun(GroupId, GroupSM0) ->
|
||||||
GroupProgresses = maps:get(Group, StreamProgresses, []),
|
GroupProgresses = maps:get(?share_topic_filter(GroupId), StreamProgresses, []),
|
||||||
emqx_ds_shared_sub_group_sm:handle_disconnect(GroupSM0, GroupProgresses)
|
emqx_ds_shared_sub_group_sm:handle_disconnect(GroupSM0, GroupProgresses)
|
||||||
end,
|
end,
|
||||||
Groups0
|
Groups0
|
||||||
),
|
),
|
||||||
State#{groups => #{}}.
|
State#{groups => #{}}.
|
||||||
|
|
||||||
on_info(State, ?leader_lease_streams_match(Group, Leader, StreamProgresses, Version)) ->
|
-spec on_info(t(), term()) -> t().
|
||||||
|
on_info(State, ?leader_lease_streams_match(GroupId, Leader, StreamProgresses, Version)) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => leader_lease_streams,
|
msg => leader_lease_streams,
|
||||||
group => Group,
|
group_id => GroupId,
|
||||||
streams => StreamProgresses,
|
streams => StreamProgresses,
|
||||||
version => Version,
|
version => Version,
|
||||||
leader => Leader
|
leader => Leader
|
||||||
}),
|
}),
|
||||||
with_group_sm(State, Group, fun(GSM) ->
|
with_group_sm(State, GroupId, fun(GSM) ->
|
||||||
emqx_ds_shared_sub_group_sm:handle_leader_lease_streams(
|
emqx_ds_shared_sub_group_sm:handle_leader_lease_streams(
|
||||||
GSM, Leader, StreamProgresses, Version
|
GSM, Leader, StreamProgresses, Version
|
||||||
)
|
)
|
||||||
end);
|
end);
|
||||||
on_info(State, ?leader_renew_stream_lease_match(Group, Version)) ->
|
on_info(State, ?leader_renew_stream_lease_match(GroupId, Version)) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => leader_renew_stream_lease,
|
msg => leader_renew_stream_lease,
|
||||||
group => Group,
|
group_id => GroupId,
|
||||||
version => Version
|
version => Version
|
||||||
}),
|
}),
|
||||||
with_group_sm(State, Group, fun(GSM) ->
|
with_group_sm(State, GroupId, fun(GSM) ->
|
||||||
emqx_ds_shared_sub_group_sm:handle_leader_renew_stream_lease(GSM, Version)
|
emqx_ds_shared_sub_group_sm:handle_leader_renew_stream_lease(GSM, Version)
|
||||||
end);
|
end);
|
||||||
on_info(State, ?leader_renew_stream_lease_match(Group, VersionOld, VersionNew)) ->
|
on_info(State, ?leader_renew_stream_lease_match(GroupId, VersionOld, VersionNew)) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => leader_renew_stream_lease,
|
msg => leader_renew_stream_lease,
|
||||||
group => Group,
|
group_id => GroupId,
|
||||||
version_old => VersionOld,
|
version_old => VersionOld,
|
||||||
version_new => VersionNew
|
version_new => VersionNew
|
||||||
}),
|
}),
|
||||||
with_group_sm(State, Group, fun(GSM) ->
|
with_group_sm(State, GroupId, fun(GSM) ->
|
||||||
emqx_ds_shared_sub_group_sm:handle_leader_renew_stream_lease(GSM, VersionOld, VersionNew)
|
emqx_ds_shared_sub_group_sm:handle_leader_renew_stream_lease(GSM, VersionOld, VersionNew)
|
||||||
end);
|
end);
|
||||||
on_info(State, ?leader_update_streams_match(Group, VersionOld, VersionNew, StreamsNew)) ->
|
on_info(State, ?leader_update_streams_match(GroupId, VersionOld, VersionNew, StreamsNew)) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => leader_update_streams,
|
msg => leader_update_streams,
|
||||||
group => Group,
|
group_id => GroupId,
|
||||||
version_old => VersionOld,
|
version_old => VersionOld,
|
||||||
version_new => VersionNew,
|
version_new => VersionNew,
|
||||||
streams_new => StreamsNew
|
streams_new => StreamsNew
|
||||||
}),
|
}),
|
||||||
with_group_sm(State, Group, fun(GSM) ->
|
with_group_sm(State, GroupId, fun(GSM) ->
|
||||||
emqx_ds_shared_sub_group_sm:handle_leader_update_streams(
|
emqx_ds_shared_sub_group_sm:handle_leader_update_streams(
|
||||||
GSM, VersionOld, VersionNew, StreamsNew
|
GSM, VersionOld, VersionNew, StreamsNew
|
||||||
)
|
)
|
||||||
end);
|
end);
|
||||||
on_info(State, ?leader_invalidate_match(Group)) ->
|
on_info(State, ?leader_invalidate_match(GroupId)) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => leader_invalidate,
|
msg => leader_invalidate,
|
||||||
group => Group
|
group_id => GroupId
|
||||||
}),
|
}),
|
||||||
with_group_sm(State, Group, fun(GSM) ->
|
with_group_sm(State, GroupId, fun(GSM) ->
|
||||||
emqx_ds_shared_sub_group_sm:handle_leader_invalidate(GSM)
|
emqx_ds_shared_sub_group_sm:handle_leader_invalidate(GSM)
|
||||||
end);
|
end);
|
||||||
%% Generic messages sent by group_sm's to themselves (timeouts).
|
%% Generic messages sent by group_sm's to themselves (timeouts).
|
||||||
on_info(State, #message_to_group_sm{group = Group, message = Message}) ->
|
on_info(State, #message_to_group_sm{group_id = GroupId, message = Message}) ->
|
||||||
with_group_sm(State, Group, fun(GSM) ->
|
with_group_sm(State, GroupId, fun(GSM) ->
|
||||||
emqx_ds_shared_sub_group_sm:handle_info(GSM, Message)
|
emqx_ds_shared_sub_group_sm:handle_info(GSM, Message)
|
||||||
end).
|
end).
|
||||||
|
|
||||||
|
@ -158,29 +217,30 @@ init_state(Opts) ->
|
||||||
groups => #{}
|
groups => #{}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
delete_group_subscription(State, #share{group = Group}, GroupProgress) ->
|
delete_shared_subscription(State, ShareTopicFilter, GroupProgress) ->
|
||||||
|
GroupId = ?group_id(ShareTopicFilter),
|
||||||
case State of
|
case State of
|
||||||
#{groups := #{Group := GSM} = Groups} ->
|
#{groups := #{GroupId := GSM} = Groups} ->
|
||||||
_ = emqx_ds_shared_sub_group_sm:handle_disconnect(GSM, GroupProgress),
|
_ = emqx_ds_shared_sub_group_sm:handle_disconnect(GSM, GroupProgress),
|
||||||
State#{groups => maps:remove(Group, Groups)};
|
State#{groups => maps:remove(GroupId, Groups)};
|
||||||
_ ->
|
_ ->
|
||||||
State
|
State
|
||||||
end.
|
end.
|
||||||
|
|
||||||
add_group_subscription(
|
add_shared_subscription(
|
||||||
#{session_id := SessionId, groups := Groups0} = State0, ShareTopicFilter
|
#{session_id := SessionId, groups := Groups0} = State0, ShareTopicFilter
|
||||||
) ->
|
) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => agent_add_group_subscription,
|
msg => agent_add_shared_subscription,
|
||||||
topic_filter => ShareTopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
#share{group = Group} = ShareTopicFilter,
|
GroupId = ?group_id(ShareTopicFilter),
|
||||||
Groups1 = Groups0#{
|
Groups1 = Groups0#{
|
||||||
Group => emqx_ds_shared_sub_group_sm:new(#{
|
GroupId => emqx_ds_shared_sub_group_sm:new(#{
|
||||||
session_id => SessionId,
|
session_id => SessionId,
|
||||||
topic_filter => ShareTopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
agent => this_agent(SessionId),
|
agent => this_agent(SessionId),
|
||||||
send_after => send_to_subscription_after(Group)
|
send_after => send_to_subscription_after(GroupId)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
State1 = State0#{groups => Groups1},
|
State1 = State0#{groups => Groups1},
|
||||||
|
@ -188,9 +248,9 @@ add_group_subscription(
|
||||||
|
|
||||||
fetch_stream_events(#{groups := Groups0} = State0) ->
|
fetch_stream_events(#{groups := Groups0} = State0) ->
|
||||||
{Groups1, Events} = maps:fold(
|
{Groups1, Events} = maps:fold(
|
||||||
fun(Group, GroupSM0, {GroupsAcc, EventsAcc}) ->
|
fun(GroupId, GroupSM0, {GroupsAcc, EventsAcc}) ->
|
||||||
{GroupSM1, Events} = emqx_ds_shared_sub_group_sm:fetch_stream_events(GroupSM0),
|
{GroupSM1, Events} = emqx_ds_shared_sub_group_sm:fetch_stream_events(GroupSM0),
|
||||||
{GroupsAcc#{Group => GroupSM1}, [Events | EventsAcc]}
|
{GroupsAcc#{GroupId => GroupSM1}, [Events | EventsAcc]}
|
||||||
end,
|
end,
|
||||||
{#{}, []},
|
{#{}, []},
|
||||||
Groups0
|
Groups0
|
||||||
|
@ -201,20 +261,20 @@ fetch_stream_events(#{groups := Groups0} = State0) ->
|
||||||
this_agent(Id) ->
|
this_agent(Id) ->
|
||||||
emqx_ds_shared_sub_proto:agent(Id, self()).
|
emqx_ds_shared_sub_proto:agent(Id, self()).
|
||||||
|
|
||||||
send_to_subscription_after(Group) ->
|
send_to_subscription_after(GroupId) ->
|
||||||
fun(Time, Msg) ->
|
fun(Time, Msg) ->
|
||||||
emqx_persistent_session_ds_shared_subs_agent:send_after(
|
emqx_persistent_session_ds_shared_subs_agent:send_after(
|
||||||
Time,
|
Time,
|
||||||
self(),
|
self(),
|
||||||
#message_to_group_sm{group = Group, message = Msg}
|
#message_to_group_sm{group_id = GroupId, message = Msg}
|
||||||
)
|
)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
with_group_sm(State, Group, Fun) ->
|
with_group_sm(State, GroupId, Fun) ->
|
||||||
case State of
|
case State of
|
||||||
#{groups := #{Group := GSM0} = Groups} ->
|
#{groups := #{GroupId := GSM0} = Groups} ->
|
||||||
#{} = GSM1 = Fun(GSM0),
|
#{} = GSM1 = Fun(GSM0),
|
||||||
State#{groups => Groups#{Group => GSM1}};
|
State#{groups => Groups#{GroupId => GSM1}};
|
||||||
_ ->
|
_ ->
|
||||||
%% TODO
|
%% TODO
|
||||||
%% Error?
|
%% Error?
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
-type options() :: #{
|
-type options() :: #{
|
||||||
session_id := emqx_persistent_session_ds:id(),
|
session_id := emqx_persistent_session_ds:id(),
|
||||||
agent := emqx_ds_shared_sub_proto:agent(),
|
agent := emqx_ds_shared_sub_proto:agent(),
|
||||||
topic_filter := emqx_persistent_session_ds:share_topic_filter(),
|
share_topic_filter := emqx_persistent_session_ds:share_topic_filter(),
|
||||||
send_after := fun((non_neg_integer(), term()) -> reference())
|
send_after := fun((non_neg_integer(), term()) -> reference())
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
@ -58,19 +58,6 @@
|
||||||
stream => emqx_ds:stream()
|
stream => emqx_ds:stream()
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-type external_lease_event() ::
|
|
||||||
#{
|
|
||||||
type => lease,
|
|
||||||
stream => emqx_ds:stream(),
|
|
||||||
progress => progress(),
|
|
||||||
topic_filter => emqx_persistent_session_ds:share_topic_filter()
|
|
||||||
}
|
|
||||||
| #{
|
|
||||||
type => revoke,
|
|
||||||
stream => emqx_ds:stream(),
|
|
||||||
topic_filter => emqx_persistent_session_ds:share_topic_filter()
|
|
||||||
}.
|
|
||||||
|
|
||||||
%% GroupSM States
|
%% GroupSM States
|
||||||
|
|
||||||
-define(connecting, connecting).
|
-define(connecting, connecting).
|
||||||
|
@ -111,7 +98,7 @@
|
||||||
-type timer() :: #timer{}.
|
-type timer() :: #timer{}.
|
||||||
|
|
||||||
-type group_sm() :: #{
|
-type group_sm() :: #{
|
||||||
topic_filter => emqx_persistent_session_ds:share_topic_filter(),
|
share_topic_filter => emqx_persistent_session_ds:share_topic_filter(),
|
||||||
agent => emqx_ds_shared_sub_proto:agent(),
|
agent => emqx_ds_shared_sub_proto:agent(),
|
||||||
send_after => fun((non_neg_integer(), term()) -> reference()),
|
send_after => fun((non_neg_integer(), term()) -> reference()),
|
||||||
stream_lease_events => list(stream_lease_event()),
|
stream_lease_events => list(stream_lease_event()),
|
||||||
|
@ -129,7 +116,7 @@
|
||||||
new(#{
|
new(#{
|
||||||
session_id := SessionId,
|
session_id := SessionId,
|
||||||
agent := Agent,
|
agent := Agent,
|
||||||
topic_filter := ShareTopicFilter,
|
share_topic_filter := ShareTopicFilter,
|
||||||
send_after := SendAfter
|
send_after := SendAfter
|
||||||
}) ->
|
}) ->
|
||||||
?SLOG(
|
?SLOG(
|
||||||
|
@ -137,32 +124,33 @@ new(#{
|
||||||
#{
|
#{
|
||||||
msg => group_sm_new,
|
msg => group_sm_new,
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
topic_filter => ShareTopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
GSM0 = #{
|
GSM0 = #{
|
||||||
id => SessionId,
|
id => SessionId,
|
||||||
topic_filter => ShareTopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
send_after => SendAfter
|
send_after => SendAfter
|
||||||
},
|
},
|
||||||
?tp(warning, group_sm_new, #{
|
?tp(warning, group_sm_new, #{
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
topic_filter => ShareTopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
transition(GSM0, ?connecting, #{}).
|
transition(GSM0, ?connecting, #{}).
|
||||||
|
|
||||||
-spec fetch_stream_events(group_sm()) -> {group_sm(), list(external_lease_event())}.
|
-spec fetch_stream_events(group_sm()) ->
|
||||||
|
{group_sm(), [emqx_ds_shared_sub_agent:external_lease_event()]}.
|
||||||
fetch_stream_events(
|
fetch_stream_events(
|
||||||
#{
|
#{
|
||||||
state := _State,
|
state := _State,
|
||||||
topic_filter := TopicFilter,
|
share_topic_filter := ShareTopicFilter,
|
||||||
stream_lease_events := Events0
|
stream_lease_events := Events0
|
||||||
} = GSM
|
} = GSM
|
||||||
) ->
|
) ->
|
||||||
Events1 = lists:map(
|
Events1 = lists:map(
|
||||||
fun(Event) ->
|
fun(Event) ->
|
||||||
Event#{topic_filter => TopicFilter}
|
Event#{share_topic_filter => ShareTopicFilter}
|
||||||
end,
|
end,
|
||||||
Events0
|
Events0
|
||||||
),
|
),
|
||||||
|
@ -187,18 +175,21 @@ handle_disconnect(
|
||||||
%%-----------------------------------------------------------------------
|
%%-----------------------------------------------------------------------
|
||||||
%% Connecting state
|
%% Connecting state
|
||||||
|
|
||||||
handle_connecting(#{agent := Agent, topic_filter := ShareTopicFilter} = GSM) ->
|
handle_connecting(#{agent := Agent, share_topic_filter := ShareTopicFilter} = GSM) ->
|
||||||
?tp(warning, group_sm_enter_connecting, #{
|
?tp(warning, group_sm_enter_connecting, #{
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
topic_filter => ShareTopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
ok = emqx_ds_shared_sub_registry:lookup_leader(Agent, agent_metadata(GSM), ShareTopicFilter),
|
ok = emqx_ds_shared_sub_registry:lookup_leader(Agent, agent_metadata(GSM), ShareTopicFilter),
|
||||||
ensure_state_timeout(GSM, find_leader_timeout, ?dq_config(session_find_leader_timeout_ms)).
|
ensure_state_timeout(GSM, find_leader_timeout, ?dq_config(session_find_leader_timeout_ms)).
|
||||||
|
|
||||||
handle_leader_lease_streams(
|
handle_leader_lease_streams(
|
||||||
#{state := ?connecting, topic_filter := TopicFilter} = GSM0, Leader, StreamProgresses, Version
|
#{state := ?connecting, share_topic_filter := ShareTopicFilter} = GSM0,
|
||||||
|
Leader,
|
||||||
|
StreamProgresses,
|
||||||
|
Version
|
||||||
) ->
|
) ->
|
||||||
?tp(debug, leader_lease_streams, #{topic_filter => TopicFilter}),
|
?tp(debug, leader_lease_streams, #{share_topic_filter => ShareTopicFilter}),
|
||||||
Streams = progresses_to_map(StreamProgresses),
|
Streams = progresses_to_map(StreamProgresses),
|
||||||
StreamLeaseEvents = progresses_to_lease_events(StreamProgresses),
|
StreamLeaseEvents = progresses_to_lease_events(StreamProgresses),
|
||||||
transition(
|
transition(
|
||||||
|
@ -215,12 +206,12 @@ handle_leader_lease_streams(
|
||||||
handle_leader_lease_streams(GSM, _Leader, _StreamProgresses, _Version) ->
|
handle_leader_lease_streams(GSM, _Leader, _StreamProgresses, _Version) ->
|
||||||
GSM.
|
GSM.
|
||||||
|
|
||||||
handle_find_leader_timeout(#{agent := Agent, topic_filter := TopicFilter} = GSM0) ->
|
handle_find_leader_timeout(#{agent := Agent, share_topic_filter := ShareTopicFilter} = GSM0) ->
|
||||||
?tp(warning, group_sm_find_leader_timeout, #{
|
?tp(warning, group_sm_find_leader_timeout, #{
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
topic_filter => TopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
ok = emqx_ds_shared_sub_registry:lookup_leader(Agent, agent_metadata(GSM0), TopicFilter),
|
ok = emqx_ds_shared_sub_registry:lookup_leader(Agent, agent_metadata(GSM0), ShareTopicFilter),
|
||||||
GSM1 = ensure_state_timeout(
|
GSM1 = ensure_state_timeout(
|
||||||
GSM0, find_leader_timeout, ?dq_config(session_find_leader_timeout_ms)
|
GSM0, find_leader_timeout, ?dq_config(session_find_leader_timeout_ms)
|
||||||
),
|
),
|
||||||
|
@ -238,8 +229,8 @@ handle_replaying(GSM0) ->
|
||||||
),
|
),
|
||||||
GSM2.
|
GSM2.
|
||||||
|
|
||||||
handle_renew_lease_timeout(#{agent := Agent, topic_filter := TopicFilter} = GSM) ->
|
handle_renew_lease_timeout(#{agent := Agent, share_topic_filter := ShareTopicFilter} = GSM) ->
|
||||||
?tp(warning, renew_lease_timeout, #{agent => Agent, topic_filter => TopicFilter}),
|
?tp(warning, renew_lease_timeout, #{agent => Agent, share_topic_filter => ShareTopicFilter}),
|
||||||
transition(GSM, ?connecting, #{}).
|
transition(GSM, ?connecting, #{}).
|
||||||
|
|
||||||
%%-----------------------------------------------------------------------
|
%%-----------------------------------------------------------------------
|
||||||
|
@ -429,10 +420,10 @@ handle_stream_progress(
|
||||||
handle_stream_progress(#{state := ?disconnected} = GSM, _StreamProgresses) ->
|
handle_stream_progress(#{state := ?disconnected} = GSM, _StreamProgresses) ->
|
||||||
GSM.
|
GSM.
|
||||||
|
|
||||||
handle_leader_invalidate(#{agent := Agent, topic_filter := TopicFilter} = GSM) ->
|
handle_leader_invalidate(#{agent := Agent, share_topic_filter := ShareTopicFilter} = GSM) ->
|
||||||
?tp(warning, shared_sub_group_sm_leader_invalidate, #{
|
?tp(warning, shared_sub_group_sm_leader_invalidate, #{
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
topic_filter => TopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
transition(GSM, ?connecting, #{}).
|
transition(GSM, ?connecting, #{}).
|
||||||
|
|
||||||
|
@ -441,11 +432,11 @@ handle_leader_invalidate(#{agent := Agent, topic_filter := TopicFilter} = GSM) -
|
||||||
%%-----------------------------------------------------------------------
|
%%-----------------------------------------------------------------------
|
||||||
|
|
||||||
handle_state_timeout(
|
handle_state_timeout(
|
||||||
#{state := ?connecting, topic_filter := TopicFilter} = GSM,
|
#{state := ?connecting, share_topic_filter := ShareTopicFilter} = GSM,
|
||||||
find_leader_timeout,
|
find_leader_timeout,
|
||||||
_Message
|
_Message
|
||||||
) ->
|
) ->
|
||||||
?tp(debug, find_leader_timeout, #{topic_filter => TopicFilter}),
|
?tp(debug, find_leader_timeout, #{share_topic_filter => ShareTopicFilter}),
|
||||||
handle_find_leader_timeout(GSM);
|
handle_find_leader_timeout(GSM);
|
||||||
handle_state_timeout(
|
handle_state_timeout(
|
||||||
#{state := ?replaying} = GSM,
|
#{state := ?replaying} = GSM,
|
||||||
|
|
|
@ -27,8 +27,12 @@
|
||||||
terminate/3
|
terminate/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-type share_topic_filter() :: emqx_persistent_session_ds:share_topic_filter().
|
||||||
|
|
||||||
|
-type group_id() :: share_topic_filter().
|
||||||
|
|
||||||
-type options() :: #{
|
-type options() :: #{
|
||||||
topic_filter := emqx_persistent_session_ds:share_topic_filter()
|
share_topic_filter := share_topic_filter()
|
||||||
}.
|
}.
|
||||||
|
|
||||||
%% Agent states
|
%% Agent states
|
||||||
|
@ -39,7 +43,7 @@
|
||||||
-define(updating, updating).
|
-define(updating, updating).
|
||||||
|
|
||||||
-type agent_state() :: #{
|
-type agent_state() :: #{
|
||||||
%% Our view of group sm's status
|
%% Our view of group_id sm's status
|
||||||
%% it lags the actual state
|
%% it lags the actual state
|
||||||
state := ?waiting_replaying | ?replaying | ?waiting_updating | ?updating,
|
state := ?waiting_replaying | ?replaying | ?waiting_updating | ?updating,
|
||||||
prev_version := emqx_maybe:t(emqx_ds_shared_sub_proto:version()),
|
prev_version := emqx_maybe:t(emqx_ds_shared_sub_proto:version()),
|
||||||
|
@ -62,7 +66,7 @@
|
||||||
%%
|
%%
|
||||||
%% Persistent data
|
%% Persistent data
|
||||||
%%
|
%%
|
||||||
group := emqx_types:group(),
|
group_id := group_id(),
|
||||||
topic := emqx_types:topic(),
|
topic := emqx_types:topic(),
|
||||||
%% For ds router, not an actual session_id
|
%% For ds router, not an actual session_id
|
||||||
router_id := binary(),
|
router_id := binary(),
|
||||||
|
@ -119,9 +123,9 @@ register(Pid, Fun) ->
|
||||||
%% Internal API
|
%% Internal API
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
child_spec(#{topic_filter := TopicFilter} = Options) ->
|
child_spec(#{share_topic_filter := ShareTopicFilter} = Options) ->
|
||||||
#{
|
#{
|
||||||
id => id(TopicFilter),
|
id => id(ShareTopicFilter),
|
||||||
start => {?MODULE, start_link, [Options]},
|
start => {?MODULE, start_link, [Options]},
|
||||||
restart => temporary,
|
restart => temporary,
|
||||||
shutdown => 5000,
|
shutdown => 5000,
|
||||||
|
@ -131,8 +135,8 @@ child_spec(#{topic_filter := TopicFilter} = Options) ->
|
||||||
start_link(Options) ->
|
start_link(Options) ->
|
||||||
gen_statem:start_link(?MODULE, [Options], []).
|
gen_statem:start_link(?MODULE, [Options], []).
|
||||||
|
|
||||||
id(#share{group = Group} = _TopicFilter) ->
|
id(ShareTopicFilter) ->
|
||||||
{?MODULE, Group}.
|
{?MODULE, ShareTopicFilter}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% gen_statem callbacks
|
%% gen_statem callbacks
|
||||||
|
@ -140,9 +144,9 @@ id(#share{group = Group} = _TopicFilter) ->
|
||||||
|
|
||||||
callback_mode() -> [handle_event_function, state_enter].
|
callback_mode() -> [handle_event_function, state_enter].
|
||||||
|
|
||||||
init([#{topic_filter := #share{group = Group, topic = Topic}} = _Options]) ->
|
init([#{share_topic_filter := #share{topic = Topic} = ShareTopicFilter} = _Options]) ->
|
||||||
Data = #{
|
Data = #{
|
||||||
group => Group,
|
group_id => ShareTopicFilter,
|
||||||
topic => Topic,
|
topic => Topic,
|
||||||
router_id => gen_router_id(),
|
router_id => gen_router_id(),
|
||||||
start_time => now_ms() - ?START_TIME_THRESHOLD,
|
start_time => now_ms() - ?START_TIME_THRESHOLD,
|
||||||
|
@ -463,14 +467,14 @@ select_streams_for_assign(Data0, _Agent, AssignCount) ->
|
||||||
%% Handle a newly connected agent
|
%% Handle a newly connected agent
|
||||||
|
|
||||||
connect_agent(
|
connect_agent(
|
||||||
#{group := Group, agents := Agents} = Data,
|
#{group_id := GroupId, agents := Agents} = Data,
|
||||||
Agent,
|
Agent,
|
||||||
AgentMetadata
|
AgentMetadata
|
||||||
) ->
|
) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => leader_agent_connected,
|
msg => leader_agent_connected,
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
group => Group
|
group_id => GroupId
|
||||||
}),
|
}),
|
||||||
case Agents of
|
case Agents of
|
||||||
#{Agent := AgentState} ->
|
#{Agent := AgentState} ->
|
||||||
|
@ -583,22 +587,22 @@ renew_leases(#{agents := AgentStates} = Data) ->
|
||||||
),
|
),
|
||||||
Data.
|
Data.
|
||||||
|
|
||||||
renew_lease(#{group := Group}, Agent, #{state := ?replaying, version := Version}) ->
|
renew_lease(#{group_id := GroupId}, Agent, #{state := ?replaying, version := Version}) ->
|
||||||
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, Group, Version);
|
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, GroupId, Version);
|
||||||
renew_lease(#{group := Group}, Agent, #{state := ?waiting_replaying, version := Version}) ->
|
renew_lease(#{group_id := GroupId}, Agent, #{state := ?waiting_replaying, version := Version}) ->
|
||||||
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, Group, Version);
|
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, GroupId, Version);
|
||||||
renew_lease(#{group := Group} = Data, Agent, #{
|
renew_lease(#{group_id := GroupId} = Data, Agent, #{
|
||||||
streams := Streams, state := ?waiting_updating, version := Version, prev_version := PrevVersion
|
streams := Streams, state := ?waiting_updating, version := Version, prev_version := PrevVersion
|
||||||
}) ->
|
}) ->
|
||||||
StreamProgresses = stream_progresses(Data, Streams),
|
StreamProgresses = stream_progresses(Data, Streams),
|
||||||
ok = emqx_ds_shared_sub_proto:leader_update_streams(
|
ok = emqx_ds_shared_sub_proto:leader_update_streams(
|
||||||
Agent, Group, PrevVersion, Version, StreamProgresses
|
Agent, GroupId, PrevVersion, Version, StreamProgresses
|
||||||
),
|
),
|
||||||
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, Group, PrevVersion, Version);
|
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, GroupId, PrevVersion, Version);
|
||||||
renew_lease(#{group := Group}, Agent, #{
|
renew_lease(#{group_id := GroupId}, Agent, #{
|
||||||
state := ?updating, version := Version, prev_version := PrevVersion
|
state := ?updating, version := Version, prev_version := PrevVersion
|
||||||
}) ->
|
}) ->
|
||||||
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, Group, PrevVersion, Version).
|
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, GroupId, PrevVersion, Version).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Handle stream progress updates from agent in replaying state
|
%% Handle stream progress updates from agent in replaying state
|
||||||
|
@ -802,7 +806,7 @@ update_agent_stream_states(Data0, Agent, AgentStreamProgresses, VersionOld, Vers
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
agent_transition_to_waiting_updating(
|
agent_transition_to_waiting_updating(
|
||||||
#{group := Group} = Data,
|
#{group_id := GroupId} = Data,
|
||||||
Agent,
|
Agent,
|
||||||
#{state := OldState, version := Version, prev_version := undefined} = AgentState0,
|
#{state := OldState, version := Version, prev_version := undefined} = AgentState0,
|
||||||
Streams,
|
Streams,
|
||||||
|
@ -825,19 +829,19 @@ agent_transition_to_waiting_updating(
|
||||||
AgentState2 = renew_no_replaying_deadline(AgentState1),
|
AgentState2 = renew_no_replaying_deadline(AgentState1),
|
||||||
StreamProgresses = stream_progresses(Data, Streams),
|
StreamProgresses = stream_progresses(Data, Streams),
|
||||||
ok = emqx_ds_shared_sub_proto:leader_update_streams(
|
ok = emqx_ds_shared_sub_proto:leader_update_streams(
|
||||||
Agent, Group, Version, NewVersion, StreamProgresses
|
Agent, GroupId, Version, NewVersion, StreamProgresses
|
||||||
),
|
),
|
||||||
AgentState2.
|
AgentState2.
|
||||||
|
|
||||||
agent_transition_to_waiting_replaying(
|
agent_transition_to_waiting_replaying(
|
||||||
#{group := Group} = _Data, Agent, #{state := OldState, version := Version} = AgentState0
|
#{group_id := GroupId} = _Data, Agent, #{state := OldState, version := Version} = AgentState0
|
||||||
) ->
|
) ->
|
||||||
?tp(warning, shared_sub_leader_agent_state_transition, #{
|
?tp(warning, shared_sub_leader_agent_state_transition, #{
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
old_state => OldState,
|
old_state => OldState,
|
||||||
new_state => ?waiting_replaying
|
new_state => ?waiting_replaying
|
||||||
}),
|
}),
|
||||||
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, Group, Version),
|
ok = emqx_ds_shared_sub_proto:leader_renew_stream_lease(Agent, GroupId, Version),
|
||||||
AgentState1 = AgentState0#{
|
AgentState1 = AgentState0#{
|
||||||
state => ?waiting_replaying,
|
state => ?waiting_replaying,
|
||||||
revoked_streams => []
|
revoked_streams => []
|
||||||
|
@ -845,7 +849,7 @@ agent_transition_to_waiting_replaying(
|
||||||
renew_no_replaying_deadline(AgentState1).
|
renew_no_replaying_deadline(AgentState1).
|
||||||
|
|
||||||
agent_transition_to_initial_waiting_replaying(
|
agent_transition_to_initial_waiting_replaying(
|
||||||
#{group := Group} = Data, Agent, AgentMetadata, InitialStreams
|
#{group_id := GroupId} = Data, Agent, AgentMetadata, InitialStreams
|
||||||
) ->
|
) ->
|
||||||
?tp(warning, shared_sub_leader_agent_state_transition, #{
|
?tp(warning, shared_sub_leader_agent_state_transition, #{
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
|
@ -856,7 +860,7 @@ agent_transition_to_initial_waiting_replaying(
|
||||||
StreamProgresses = stream_progresses(Data, InitialStreams),
|
StreamProgresses = stream_progresses(Data, InitialStreams),
|
||||||
Leader = this_leader(Data),
|
Leader = this_leader(Data),
|
||||||
ok = emqx_ds_shared_sub_proto:leader_lease_streams(
|
ok = emqx_ds_shared_sub_proto:leader_lease_streams(
|
||||||
Agent, Group, Leader, StreamProgresses, Version
|
Agent, GroupId, Leader, StreamProgresses, Version
|
||||||
),
|
),
|
||||||
AgentState = #{
|
AgentState = #{
|
||||||
metadata => AgentMetadata,
|
metadata => AgentMetadata,
|
||||||
|
@ -1015,8 +1019,8 @@ drop_agent(#{agents := Agents} = Data0, Agent) ->
|
||||||
?tp(warning, shared_sub_leader_drop_agent, #{agent => Agent}),
|
?tp(warning, shared_sub_leader_drop_agent, #{agent => Agent}),
|
||||||
Data1#{agents => maps:remove(Agent, Agents)}.
|
Data1#{agents => maps:remove(Agent, Agents)}.
|
||||||
|
|
||||||
invalidate_agent(#{group := Group}, Agent) ->
|
invalidate_agent(#{group_id := GroupId}, Agent) ->
|
||||||
ok = emqx_ds_shared_sub_proto:leader_invalidate(Agent, Group).
|
ok = emqx_ds_shared_sub_proto:leader_invalidate(Agent, GroupId).
|
||||||
|
|
||||||
drop_invalidate_agent(Data0, Agent) ->
|
drop_invalidate_agent(Data0, Agent) ->
|
||||||
Data1 = drop_agent(Data0, Agent),
|
Data1 = drop_agent(Data0, Agent),
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
-type agent() :: ?agent(emqx_persistent_session_ds:id(), pid()).
|
-type agent() :: ?agent(emqx_persistent_session_ds:id(), pid()).
|
||||||
-type leader() :: pid().
|
-type leader() :: pid().
|
||||||
-type topic_filter() :: emqx_persistent_session_ds:share_topic_filter().
|
-type share_topic_filter() :: emqx_persistent_session_ds:share_topic_filter().
|
||||||
-type group() :: emqx_types:group().
|
-type group() :: emqx_types:group().
|
||||||
-type version() :: non_neg_integer().
|
-type version() :: non_neg_integer().
|
||||||
-type agent_metadata() :: #{
|
-type agent_metadata() :: #{
|
||||||
|
@ -63,8 +63,8 @@
|
||||||
|
|
||||||
%% agent -> leader messages
|
%% agent -> leader messages
|
||||||
|
|
||||||
-spec agent_connect_leader(leader(), agent(), agent_metadata(), topic_filter()) -> ok.
|
-spec agent_connect_leader(leader(), agent(), agent_metadata(), share_topic_filter()) -> ok.
|
||||||
agent_connect_leader(ToLeader, FromAgent, AgentMetadata, TopicFilter) when
|
agent_connect_leader(ToLeader, FromAgent, AgentMetadata, ShareTopicFilter) when
|
||||||
?is_local_leader(ToLeader)
|
?is_local_leader(ToLeader)
|
||||||
->
|
->
|
||||||
?tp(warning, shared_sub_proto_msg, #{
|
?tp(warning, shared_sub_proto_msg, #{
|
||||||
|
@ -72,13 +72,13 @@ agent_connect_leader(ToLeader, FromAgent, AgentMetadata, TopicFilter) when
|
||||||
to_leader => ToLeader,
|
to_leader => ToLeader,
|
||||||
from_agent => FromAgent,
|
from_agent => FromAgent,
|
||||||
agent_metadata => AgentMetadata,
|
agent_metadata => AgentMetadata,
|
||||||
topic_filter => TopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
_ = erlang:send(ToLeader, ?agent_connect_leader(FromAgent, AgentMetadata, TopicFilter)),
|
_ = erlang:send(ToLeader, ?agent_connect_leader(FromAgent, AgentMetadata, ShareTopicFilter)),
|
||||||
ok;
|
ok;
|
||||||
agent_connect_leader(ToLeader, FromAgent, AgentMetadata, TopicFilter) ->
|
agent_connect_leader(ToLeader, FromAgent, AgentMetadata, ShareTopicFilter) ->
|
||||||
emqx_ds_shared_sub_proto_v1:agent_connect_leader(
|
emqx_ds_shared_sub_proto_v1:agent_connect_leader(
|
||||||
?leader_node(ToLeader), ToLeader, FromAgent, AgentMetadata, TopicFilter
|
?leader_node(ToLeader), ToLeader, FromAgent, AgentMetadata, ShareTopicFilter
|
||||||
).
|
).
|
||||||
|
|
||||||
-spec agent_update_stream_states(leader(), agent(), list(agent_stream_progress()), version()) -> ok.
|
-spec agent_update_stream_states(leader(), agent(), list(agent_stream_progress()), version()) -> ok.
|
||||||
|
|
|
@ -21,16 +21,16 @@
|
||||||
%% Agent messages sent to the leader.
|
%% Agent messages sent to the leader.
|
||||||
%% Leader talks to many agents, `agent` field is used to identify the sender.
|
%% Leader talks to many agents, `agent` field is used to identify the sender.
|
||||||
|
|
||||||
-define(agent_connect_leader(Agent, AgentMetadata, TopicFilter), #{
|
-define(agent_connect_leader(Agent, AgentMetadata, ShareTopicFilter), #{
|
||||||
type => ?agent_connect_leader_msg,
|
type => ?agent_connect_leader_msg,
|
||||||
topic_filter => TopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
agent_metadata => AgentMetadata,
|
agent_metadata => AgentMetadata,
|
||||||
agent => Agent
|
agent => Agent
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(agent_connect_leader_match(Agent, AgentMetadata, TopicFilter), #{
|
-define(agent_connect_leader_match(Agent, AgentMetadata, ShareTopicFilter), #{
|
||||||
type := ?agent_connect_leader_msg,
|
type := ?agent_connect_leader_msg,
|
||||||
topic_filter := TopicFilter,
|
share_topic_filter := ShareTopicFilter,
|
||||||
agent_metadata := AgentMetadata,
|
agent_metadata := AgentMetadata,
|
||||||
agent := Agent
|
agent := Agent
|
||||||
}).
|
}).
|
||||||
|
@ -81,77 +81,77 @@
|
||||||
|
|
||||||
%% leader messages, sent from the leader to the agent
|
%% leader messages, sent from the leader to the agent
|
||||||
%% Agent may have several shared subscriptions, so may talk to several leaders
|
%% Agent may have several shared subscriptions, so may talk to several leaders
|
||||||
%% `group` field is used to identify the leader.
|
%% `group_id` field is used to identify the leader.
|
||||||
|
|
||||||
-define(leader_lease_streams_msg, leader_lease_streams).
|
-define(leader_lease_streams_msg, leader_lease_streams).
|
||||||
-define(leader_renew_stream_lease_msg, leader_renew_stream_lease).
|
-define(leader_renew_stream_lease_msg, leader_renew_stream_lease).
|
||||||
|
|
||||||
-define(leader_lease_streams(Group, Leader, Streams, Version), #{
|
-define(leader_lease_streams(GrouId, Leader, Streams, Version), #{
|
||||||
type => ?leader_lease_streams_msg,
|
type => ?leader_lease_streams_msg,
|
||||||
streams => Streams,
|
streams => Streams,
|
||||||
version => Version,
|
version => Version,
|
||||||
leader => Leader,
|
leader => Leader,
|
||||||
group => Group
|
group_id => GrouId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_lease_streams_match(Group, Leader, Streams, Version), #{
|
-define(leader_lease_streams_match(GroupId, Leader, Streams, Version), #{
|
||||||
type := ?leader_lease_streams_msg,
|
type := ?leader_lease_streams_msg,
|
||||||
streams := Streams,
|
streams := Streams,
|
||||||
version := Version,
|
version := Version,
|
||||||
leader := Leader,
|
leader := Leader,
|
||||||
group := Group
|
group_id := GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_renew_stream_lease(Group, Version), #{
|
-define(leader_renew_stream_lease(GroupId, Version), #{
|
||||||
type => ?leader_renew_stream_lease_msg,
|
type => ?leader_renew_stream_lease_msg,
|
||||||
version => Version,
|
version => Version,
|
||||||
group => Group
|
group_id => GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_renew_stream_lease_match(Group, Version), #{
|
-define(leader_renew_stream_lease_match(GroupId, Version), #{
|
||||||
type := ?leader_renew_stream_lease_msg,
|
type := ?leader_renew_stream_lease_msg,
|
||||||
version := Version,
|
version := Version,
|
||||||
group := Group
|
group_id := GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_renew_stream_lease(Group, VersionOld, VersionNew), #{
|
-define(leader_renew_stream_lease(GroupId, VersionOld, VersionNew), #{
|
||||||
type => ?leader_renew_stream_lease_msg,
|
type => ?leader_renew_stream_lease_msg,
|
||||||
version_old => VersionOld,
|
version_old => VersionOld,
|
||||||
version_new => VersionNew,
|
version_new => VersionNew,
|
||||||
group => Group
|
group_id => GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_renew_stream_lease_match(Group, VersionOld, VersionNew), #{
|
-define(leader_renew_stream_lease_match(GroupId, VersionOld, VersionNew), #{
|
||||||
type := ?leader_renew_stream_lease_msg,
|
type := ?leader_renew_stream_lease_msg,
|
||||||
version_old := VersionOld,
|
version_old := VersionOld,
|
||||||
version_new := VersionNew,
|
version_new := VersionNew,
|
||||||
group := Group
|
group_id := GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_update_streams(Group, VersionOld, VersionNew, StreamsNew), #{
|
-define(leader_update_streams(GroupId, VersionOld, VersionNew, StreamsNew), #{
|
||||||
type => leader_update_streams,
|
type => leader_update_streams,
|
||||||
version_old => VersionOld,
|
version_old => VersionOld,
|
||||||
version_new => VersionNew,
|
version_new => VersionNew,
|
||||||
streams_new => StreamsNew,
|
streams_new => StreamsNew,
|
||||||
group => Group
|
group_id => GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_update_streams_match(Group, VersionOld, VersionNew, StreamsNew), #{
|
-define(leader_update_streams_match(GroupId, VersionOld, VersionNew, StreamsNew), #{
|
||||||
type := leader_update_streams,
|
type := leader_update_streams,
|
||||||
version_old := VersionOld,
|
version_old := VersionOld,
|
||||||
version_new := VersionNew,
|
version_new := VersionNew,
|
||||||
streams_new := StreamsNew,
|
streams_new := StreamsNew,
|
||||||
group := Group
|
group_id := GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_invalidate(Group), #{
|
-define(leader_invalidate(GroupId), #{
|
||||||
type => leader_invalidate,
|
type => leader_invalidate,
|
||||||
group => Group
|
group_id => GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(leader_invalidate_match(Group), #{
|
-define(leader_invalidate_match(GroupId), #{
|
||||||
type := leader_invalidate,
|
type := leader_invalidate,
|
||||||
group := Group
|
group_id := GroupId
|
||||||
}).
|
}).
|
||||||
|
|
||||||
%% Helpers
|
%% Helpers
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
-record(lookup_leader, {
|
-record(lookup_leader, {
|
||||||
agent :: emqx_ds_shared_sub_proto:agent(),
|
agent :: emqx_ds_shared_sub_proto:agent(),
|
||||||
agent_metadata :: emqx_ds_shared_sub_proto:agent_metadata(),
|
agent_metadata :: emqx_ds_shared_sub_proto:agent_metadata(),
|
||||||
topic_filter :: emqx_persistent_session_ds:share_topic_filter()
|
share_topic_filter :: emqx_persistent_session_ds:share_topic_filter()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-define(gproc_id(ID), {n, l, ID}).
|
-define(gproc_id(ID), {n, l, ID}).
|
||||||
|
@ -40,9 +40,9 @@
|
||||||
emqx_ds_shared_sub_proto:agent_metadata(),
|
emqx_ds_shared_sub_proto:agent_metadata(),
|
||||||
emqx_persistent_session_ds:share_topic_filter()
|
emqx_persistent_session_ds:share_topic_filter()
|
||||||
) -> ok.
|
) -> ok.
|
||||||
lookup_leader(Agent, AgentMetadata, TopicFilter) ->
|
lookup_leader(Agent, AgentMetadata, ShareTopicFilter) ->
|
||||||
gen_server:cast(?MODULE, #lookup_leader{
|
gen_server:cast(?MODULE, #lookup_leader{
|
||||||
agent = Agent, agent_metadata = AgentMetadata, topic_filter = TopicFilter
|
agent = Agent, agent_metadata = AgentMetadata, share_topic_filter = ShareTopicFilter
|
||||||
}).
|
}).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -72,9 +72,14 @@ handle_call(_Request, _From, State) ->
|
||||||
{reply, {error, unknown_request}, State}.
|
{reply, {error, unknown_request}, State}.
|
||||||
|
|
||||||
handle_cast(
|
handle_cast(
|
||||||
#lookup_leader{agent = Agent, agent_metadata = AgentMetadata, topic_filter = TopicFilter}, State
|
#lookup_leader{
|
||||||
|
agent = Agent,
|
||||||
|
agent_metadata = AgentMetadata,
|
||||||
|
share_topic_filter = ShareTopicFilter
|
||||||
|
},
|
||||||
|
State
|
||||||
) ->
|
) ->
|
||||||
State1 = do_lookup_leader(Agent, AgentMetadata, TopicFilter, State),
|
State1 = do_lookup_leader(Agent, AgentMetadata, ShareTopicFilter, State),
|
||||||
{noreply, State1}.
|
{noreply, State1}.
|
||||||
|
|
||||||
handle_info(_Info, State) ->
|
handle_info(_Info, State) ->
|
||||||
|
@ -87,15 +92,15 @@ terminate(_Reason, _State) ->
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
do_lookup_leader(Agent, AgentMetadata, TopicFilter, State) ->
|
do_lookup_leader(Agent, AgentMetadata, ShareTopicFilter, State) ->
|
||||||
%% TODO https://emqx.atlassian.net/browse/EMQX-12309
|
%% TODO https://emqx.atlassian.net/browse/EMQX-12309
|
||||||
%% Cluster-wide unique leader election should be implemented
|
%% Cluster-wide unique leader election should be implemented
|
||||||
Id = emqx_ds_shared_sub_leader:id(TopicFilter),
|
Id = emqx_ds_shared_sub_leader:id(ShareTopicFilter),
|
||||||
LeaderPid =
|
LeaderPid =
|
||||||
case gproc:where(?gproc_id(Id)) of
|
case gproc:where(?gproc_id(Id)) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{ok, Pid} = emqx_ds_shared_sub_leader_sup:start_leader(#{
|
{ok, Pid} = emqx_ds_shared_sub_leader_sup:start_leader(#{
|
||||||
topic_filter => TopicFilter
|
share_topic_filter => ShareTopicFilter
|
||||||
}),
|
}),
|
||||||
{ok, NewLeaderPid} = emqx_ds_shared_sub_leader:register(
|
{ok, NewLeaderPid} = emqx_ds_shared_sub_leader:register(
|
||||||
Pid,
|
Pid,
|
||||||
|
@ -111,10 +116,10 @@ do_lookup_leader(Agent, AgentMetadata, TopicFilter, State) ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => lookup_leader,
|
msg => lookup_leader,
|
||||||
agent => Agent,
|
agent => Agent,
|
||||||
topic_filter => TopicFilter,
|
share_topic_filter => ShareTopicFilter,
|
||||||
leader => LeaderPid
|
leader => LeaderPid
|
||||||
}),
|
}),
|
||||||
ok = emqx_ds_shared_sub_proto:agent_connect_leader(
|
ok = emqx_ds_shared_sub_proto:agent_connect_leader(
|
||||||
LeaderPid, Agent, AgentMetadata, TopicFilter
|
LeaderPid, Agent, AgentMetadata, ShareTopicFilter
|
||||||
),
|
),
|
||||||
State.
|
State.
|
||||||
|
|
|
@ -33,9 +33,9 @@ introduced_in() ->
|
||||||
emqx_ds_shared_sub_proto:agent_metadata(),
|
emqx_ds_shared_sub_proto:agent_metadata(),
|
||||||
emqx_persistent_session_ds:share_topic_filter()
|
emqx_persistent_session_ds:share_topic_filter()
|
||||||
) -> ok.
|
) -> ok.
|
||||||
agent_connect_leader(Node, ToLeader, FromAgent, AgentMetadata, TopicFilter) ->
|
agent_connect_leader(Node, ToLeader, FromAgent, AgentMetadata, ShareTopicFilter) ->
|
||||||
erpc:cast(Node, emqx_ds_shared_sub_proto, agent_connect_leader, [
|
erpc:cast(Node, emqx_ds_shared_sub_proto, agent_connect_leader, [
|
||||||
ToLeader, FromAgent, AgentMetadata, TopicFilter
|
ToLeader, FromAgent, AgentMetadata, ShareTopicFilter
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-spec agent_update_stream_states(
|
-spec agent_update_stream_states(
|
||||||
|
|
Loading…
Reference in New Issue