27
27
handle_info /2 ,
28
28
terminate /2 ,
29
29
code_change /3 ]).
30
- -export ([register_consumer /4 ]).
30
+ -export ([register_consumer /5 ,
31
+ unregister_consumer /5 ]).
31
32
33
+ -type vhost () :: binary ().
32
34
-type stream () :: binary ().
33
35
-type consumer_name () :: binary ().
34
36
-type subscription_id () :: byte ().
35
37
36
38
-record (consumer ,
37
39
{pid :: pid (), subscription_id :: subscription_id ()}).
38
40
-record (group , {consumers :: [# consumer {}]}).
39
- -record (stream_groups , { groups :: #{ consumer_name () => # group {}}}).
40
- - record ( state , { stream_groups :: #{stream () => # stream_groups {}}}).
41
+ -record (state ,
42
+ { groups :: #{{ vhost (), stream (), consumer_name ()} => # group {}}}).
41
43
42
- register_consumer (Stream ,
44
+ register_consumer (VirtualHost ,
45
+ Stream ,
43
46
ConsumerName ,
44
47
ConnectionPid ,
45
48
SubscriptionId ) ->
46
49
call ({register_consumer ,
50
+ VirtualHost ,
51
+ Stream ,
52
+ ConsumerName ,
53
+ ConnectionPid ,
54
+ SubscriptionId }).
55
+
56
+ unregister_consumer (VirtualHost ,
57
+ Stream ,
58
+ ConsumerName ,
59
+ ConnectionPid ,
60
+ SubscriptionId ) ->
61
+ call ({unregister_consumer ,
62
+ VirtualHost ,
47
63
Stream ,
48
64
ConsumerName ,
49
65
ConnectionPid ,
@@ -86,7 +102,7 @@ start_link() ->
86
102
% % @end
87
103
% %--------------------------------------------------------------------
88
104
init ([]) ->
89
- {ok , # state {stream_groups = #{}}}.
105
+ {ok , # state {groups = #{}}}.
90
106
91
107
% %--------------------------------------------------------------------
92
108
% % @private
@@ -103,50 +119,110 @@ init([]) ->
103
119
% % @end
104
120
% %--------------------------------------------------------------------
105
121
handle_call ({register_consumer ,
122
+ VirtualHost ,
106
123
Stream ,
107
124
ConsumerName ,
108
125
ConnectionPid ,
109
126
SubscriptionId },
110
- _From , # state {stream_groups = StreamGroups0 } = State ) ->
127
+ _From , # state {groups = StreamGroups0 } = State ) ->
111
128
StreamGroups1 =
112
- maybe_create_group (Stream , ConsumerName , StreamGroups0 ),
113
- Group0 = lookup_group (Stream , ConsumerName , StreamGroups1 ),
129
+ maybe_create_group (VirtualHost , Stream , ConsumerName , StreamGroups0 ),
130
+ Group0 =
131
+ lookup_group (VirtualHost , Stream , ConsumerName , StreamGroups1 ),
114
132
Consumer =
115
133
# consumer {pid = ConnectionPid , subscription_id = SubscriptionId },
116
134
Group = add_to_group (Consumer , Group0 ),
117
135
Active = is_active (Consumer , Group ),
118
136
StreamGroups2 =
119
- update_groups (Stream , ConsumerName , Group , StreamGroups1 ),
120
- {reply , {ok , Active }, State # state {stream_groups = StreamGroups2 }};
137
+ update_groups (VirtualHost ,
138
+ Stream ,
139
+ ConsumerName ,
140
+ Group ,
141
+ StreamGroups1 ),
142
+ {reply , {ok , Active }, State # state {groups = StreamGroups2 }};
143
+ handle_call ({unregister_consumer ,
144
+ VirtualHost ,
145
+ Stream ,
146
+ ConsumerName ,
147
+ ConnectionPid ,
148
+ SubscriptionId },
149
+ _From , # state {groups = StreamGroups0 } = State0 ) ->
150
+ State1 =
151
+ case lookup_group (VirtualHost , Stream , ConsumerName , StreamGroups0 ) of
152
+ error ->
153
+ State0 ;
154
+ Group0 ->
155
+ # group {consumers = Consumers0 } = Group0 ,
156
+ Consumers1 =
157
+ case lists :search (fun (# consumer {pid = ConnPid ,
158
+ subscription_id = SubId }) ->
159
+ ConnPid == ConnectionPid
160
+ andalso SubId == SubscriptionId
161
+ end ,
162
+ Consumers0 )
163
+ of
164
+ {value , Consumer } ->
165
+ rabbit_log :debug (" Unregistering consumer ~p from group" ,
166
+ [Consumer ]),
167
+ case lists :nth (1 , Consumers0 ) of
168
+ Consumer ->
169
+ rabbit_log :debug (" Unregistering the active consumer" ),
170
+ % % this is active one, remove it and notify the new active one if group not empty
171
+ Cs = lists :delete (Consumer , Consumers0 ),
172
+ case Cs of
173
+ [] ->
174
+ % % group is empty now
175
+ rabbit_log :debug (" Group is now empty" ),
176
+ ok ;
177
+ _ ->
178
+ % % get new active one (the first) and notify it
179
+ # consumer {pid = Pid ,
180
+ subscription_id = SubId } =
181
+ lists :nth (1 , Cs ),
182
+ rabbit_log :debug (" New active consumer is ~p ~p " ,
183
+ [Pid , SubId ]),
184
+ Pid
185
+ ! {sac ,
186
+ {{subscription_id , SubId },
187
+ {active , true }}}
188
+ end ,
189
+ Cs ;
190
+ _ActiveConsumer ->
191
+ rabbit_log :debug (" Not the active consumer, just removing from the "
192
+ " group" ),
193
+ lists :delete (Consumer , Consumers0 )
194
+ end ;
195
+ error ->
196
+ rabbit_log :debug (" Could not find consumer ~p ~p in group ~p ~p ~p " ,
197
+ [ConnectionPid ,
198
+ SubscriptionId ,
199
+ VirtualHost ,
200
+ Stream ,
201
+ ConsumerName ]),
202
+ Consumers0
203
+ end ,
204
+ SGS = update_groups (VirtualHost ,
205
+ Stream ,
206
+ ConsumerName ,
207
+ Group0 # group {consumers = Consumers1 },
208
+ StreamGroups0 ),
209
+ State0 # state {groups = SGS }
210
+ end ,
211
+ {reply , ok , State1 };
121
212
handle_call (which_children , _From , State ) ->
122
213
{reply , [], State }.
123
214
124
- maybe_create_group (Stream , ConsumerName , StreamGroups ) ->
215
+ maybe_create_group (VirtualHost , Stream , ConsumerName , StreamGroups ) ->
125
216
case StreamGroups of
126
- #{Stream := # stream_groups {groups = #{ConsumerName := _Consumers }}} ->
127
- % % the group already exists
217
+ #{{VirtualHost , Stream , ConsumerName } := _Group } ->
128
218
StreamGroups ;
129
- #{Stream := # stream_groups {groups = GroupsForTheStream } = SG } ->
130
- % % there are groups for this streams, but not one for this consumer name
131
- GroupsForTheStream1 =
132
- maps :put (ConsumerName , # group {consumers = []},
133
- GroupsForTheStream ),
134
- StreamGroups #{Stream =>
135
- SG # stream_groups {groups = GroupsForTheStream1 }};
136
219
SGS ->
137
- SG = maps :get (Stream , SGS , # stream_groups {groups = #{}}),
138
- # stream_groups {groups = Groups } = SG ,
139
- Groups1 = maps :put (ConsumerName , # group {consumers = []}, Groups ),
140
- SGS #{Stream => SG # stream_groups {groups = Groups1 }}
220
+ maps :put ({VirtualHost , Stream , ConsumerName },
221
+ # group {consumers = []}, SGS )
141
222
end .
142
223
143
- lookup_group (Stream , ConsumerName , StreamGroups ) ->
144
- case StreamGroups of
145
- #{Stream := # stream_groups {groups = #{ConsumerName := Group }}} ->
146
- Group ;
147
- _ ->
148
- error
149
- end .
224
+ lookup_group (VirtualHost , Stream , ConsumerName , StreamGroups ) ->
225
+ maps :get ({VirtualHost , Stream , ConsumerName }, StreamGroups ).
150
226
151
227
add_to_group (Consumer , # group {consumers = Consumers } = Group ) ->
152
228
Group # group {consumers = Consumers ++ [Consumer ]}.
@@ -158,10 +234,20 @@ is_active(Consumer, #group{consumers = [Consumer | _]}) ->
158
234
is_active (_ , _ ) ->
159
235
false .
160
236
161
- update_groups (Stream , ConsumerName , Group , StreamGroups ) ->
162
- #{Stream := # stream_groups {groups = Groups }} = StreamGroups ,
163
- Groups1 = maps :put (ConsumerName , Group , Groups ),
164
- StreamGroups #{Stream => # stream_groups {groups = Groups1 }}.
237
+ update_groups (VirtualHost ,
238
+ Stream ,
239
+ ConsumerName ,
240
+ # group {consumers = []},
241
+ StreamGroups ) ->
242
+ rabbit_log :debug (" Group ~p ~p ~p is now empty, removing it" ,
243
+ [VirtualHost , Stream , ConsumerName ]),
244
+ maps :remove ({VirtualHost , Stream , ConsumerName }, StreamGroups );
245
+ update_groups (VirtualHost ,
246
+ Stream ,
247
+ ConsumerName ,
248
+ Group ,
249
+ StreamGroups ) ->
250
+ maps :put ({VirtualHost , Stream , ConsumerName }, Group , StreamGroups ).
165
251
166
252
handle_cast (_Msg , State ) ->
167
253
{noreply , State }.
0 commit comments