@@ -250,70 +250,10 @@ private CompletableFuture<Void> addConsumerInternal(Consumer consumer) {
250
250
}
251
251
252
252
if (dispatcher == null || !dispatcher .isConsumerConnected ()) {
253
- Dispatcher previousDispatcher = null ;
254
- switch (consumer .subType ()) {
255
- case Exclusive :
256
- if (dispatcher == null || dispatcher .getType () != SubType .Exclusive ) {
257
- previousDispatcher = dispatcher ;
258
- dispatcher = new PersistentDispatcherSingleActiveConsumer (
259
- cursor , SubType .Exclusive , 0 , topic , this );
260
- }
261
- break ;
262
- case Shared :
263
- if (dispatcher == null || dispatcher .getType () != SubType .Shared ) {
264
- previousDispatcher = dispatcher ;
265
- if (config .isSubscriptionSharedUseClassicPersistentImplementation ()) {
266
- dispatcher = new PersistentDispatcherMultipleConsumersClassic (topic , cursor , this );
267
- } else {
268
- dispatcher = new PersistentDispatcherMultipleConsumers (topic , cursor , this );
269
- }
270
- }
271
- break ;
272
- case Failover :
273
- int partitionIndex = TopicName .getPartitionIndex (topicName );
274
- if (partitionIndex < 0 ) {
275
- // For non partition topics, use a negative index so
276
- // dispatcher won't sort consumers before picking
277
- // an active consumer for the topic.
278
- partitionIndex = -1 ;
279
- }
280
-
281
- if (dispatcher == null || dispatcher .getType () != SubType .Failover ) {
282
- previousDispatcher = dispatcher ;
283
- dispatcher = new PersistentDispatcherSingleActiveConsumer (cursor , SubType .Failover ,
284
- partitionIndex , topic , this );
285
- }
286
- break ;
287
- case Key_Shared :
288
- KeySharedMeta ksm = consumer .getKeySharedMeta ();
289
- if (dispatcher == null || dispatcher .getType () != SubType .Key_Shared
290
- || !((StickyKeyDispatcher ) dispatcher )
291
- .hasSameKeySharedPolicy (ksm )) {
292
- previousDispatcher = dispatcher ;
293
- if (config .isSubscriptionKeySharedUseClassicPersistentImplementation ()) {
294
- dispatcher =
295
- new PersistentStickyKeyDispatcherMultipleConsumersClassic (topic , cursor ,
296
- this ,
297
- topic .getBrokerService ().getPulsar ().getConfiguration (), ksm );
298
- } else {
299
- dispatcher = new PersistentStickyKeyDispatcherMultipleConsumers (topic , cursor , this ,
300
- topic .getBrokerService ().getPulsar ().getConfiguration (), ksm );
301
- }
302
- }
303
- break ;
304
- default :
305
- return FutureUtil .failedFuture (
306
- new ServerMetadataException ("Unsupported subscription type" ));
307
- }
308
-
309
- if (previousDispatcher != null ) {
310
- previousDispatcher .close ().thenRun (() -> {
311
- log .info ("[{}][{}] Successfully closed previous dispatcher" , topicName , subName );
312
- }).exceptionally (ex -> {
313
- log .error ("[{}][{}] Failed to close previous dispatcher" , topicName , subName , ex );
314
- return null ;
315
- });
253
+ if (consumer .subType () == null ) {
254
+ return FutureUtil .failedFuture (new ServerMetadataException ("Unsupported subscription type" ));
316
255
}
256
+ dispatcher = reuseOrCreateDispatcher (dispatcher , consumer );
317
257
} else {
318
258
Optional <CompletableFuture <Void >> compatibilityError =
319
259
checkForConsumerCompatibilityErrorWithDispatcher (dispatcher , consumer );
@@ -327,6 +267,79 @@ private CompletableFuture<Void> addConsumerInternal(Consumer consumer) {
327
267
});
328
268
}
329
269
270
+ /**
271
+ * Create a new dispatcher or reuse the existing one when it's compatible with the new consumer.
272
+ * This protected method can be overridded for testing purpose for injecting test dispatcher instances with
273
+ * special behaviors.
274
+ * @param dispatcher the existing dispatcher
275
+ * @param consumer the new consumer
276
+ * @return the dispatcher to use, either the existing one or a new one
277
+ */
278
+ protected Dispatcher reuseOrCreateDispatcher (Dispatcher dispatcher , Consumer consumer ) {
279
+ Dispatcher previousDispatcher = null ;
280
+ switch (consumer .subType ()) {
281
+ case Exclusive :
282
+ if (dispatcher == null || dispatcher .getType () != SubType .Exclusive ) {
283
+ previousDispatcher = dispatcher ;
284
+ dispatcher = new PersistentDispatcherSingleActiveConsumer (
285
+ cursor , SubType .Exclusive , 0 , topic , this );
286
+ }
287
+ break ;
288
+ case Shared :
289
+ if (dispatcher == null || dispatcher .getType () != SubType .Shared ) {
290
+ previousDispatcher = dispatcher ;
291
+ if (config .isSubscriptionSharedUseClassicPersistentImplementation ()) {
292
+ dispatcher = new PersistentDispatcherMultipleConsumersClassic (topic , cursor , this );
293
+ } else {
294
+ dispatcher = new PersistentDispatcherMultipleConsumers (topic , cursor , this );
295
+ }
296
+ }
297
+ break ;
298
+ case Failover :
299
+ int partitionIndex = TopicName .getPartitionIndex (topicName );
300
+ if (partitionIndex < 0 ) {
301
+ // For non partition topics, use a negative index so
302
+ // dispatcher won't sort consumers before picking
303
+ // an active consumer for the topic.
304
+ partitionIndex = -1 ;
305
+ }
306
+
307
+ if (dispatcher == null || dispatcher .getType () != SubType .Failover ) {
308
+ previousDispatcher = dispatcher ;
309
+ dispatcher = new PersistentDispatcherSingleActiveConsumer (cursor , SubType .Failover ,
310
+ partitionIndex , topic , this );
311
+ }
312
+ break ;
313
+ case Key_Shared :
314
+ KeySharedMeta ksm = consumer .getKeySharedMeta ();
315
+ if (dispatcher == null || dispatcher .getType () != SubType .Key_Shared
316
+ || !((StickyKeyDispatcher ) dispatcher )
317
+ .hasSameKeySharedPolicy (ksm )) {
318
+ previousDispatcher = dispatcher ;
319
+ if (config .isSubscriptionKeySharedUseClassicPersistentImplementation ()) {
320
+ dispatcher =
321
+ new PersistentStickyKeyDispatcherMultipleConsumersClassic (topic , cursor ,
322
+ this , config , ksm );
323
+ } else {
324
+ dispatcher = new PersistentStickyKeyDispatcherMultipleConsumers (topic , cursor , this ,
325
+ config , ksm );
326
+ }
327
+ }
328
+ break ;
329
+ }
330
+
331
+ if (previousDispatcher != null ) {
332
+ previousDispatcher .close ().thenRun (() -> {
333
+ log .info ("[{}][{}] Successfully closed previous dispatcher" , topicName , subName );
334
+ }).exceptionally (ex -> {
335
+ log .error ("[{}][{}] Failed to close previous dispatcher" , topicName , subName , ex );
336
+ return null ;
337
+ });
338
+ }
339
+
340
+ return dispatcher ;
341
+ }
342
+
330
343
@ Override
331
344
public synchronized void removeConsumer (Consumer consumer , boolean isResetCursor ) throws BrokerServiceException {
332
345
cursor .updateLastActive ();
0 commit comments