@@ -40,7 +40,10 @@ public record ClientParameters
4040 { "product" , "RabbitMQ Stream" } ,
4141 { "version" , Version . VersionString } ,
4242 { "platform" , ".NET" } ,
43- { "copyright" , "Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term Broadcom refers to Broadcom Inc. and/or its subsidiaries." } ,
43+ {
44+ "copyright" ,
45+ "Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term Broadcom refers to Broadcom Inc. and/or its subsidiaries."
46+ } ,
4447 {
4548 "information" ,
4649 "Licensed under the Apache 2.0 and MPL 2.0 licenses. See https://www.rabbitmq.com/"
@@ -53,7 +56,7 @@ public record ClientParameters
5356 public string VirtualHost { get ; set ; } = "/" ;
5457 public EndPoint Endpoint { get ; set ; } = new IPEndPoint ( IPAddress . Loopback , 5552 ) ;
5558
56- public delegate void MetadataUpdateHandler ( MetaDataUpdate update ) ;
59+ public delegate Task MetadataUpdateHandler ( MetaDataUpdate update ) ;
5760
5861 public event MetadataUpdateHandler OnMetadataUpdate ;
5962 public Action < Exception > UnhandledExceptionHandler { get ; set ; } = _ => { } ;
@@ -121,12 +124,13 @@ public class Client : IClient
121124 private readonly TaskCompletionSource < TuneResponse > tuneReceived =
122125 new TaskCompletionSource < TuneResponse > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
123126
124- internal readonly IDictionary < byte , ( Action < ReadOnlyMemory < ulong > > , Action < ( ulong , ResponseCode ) [ ] > ) >
127+ internal readonly IDictionary < byte , ( string , ( Action < ReadOnlyMemory < ulong > > , Action < ( ulong , ResponseCode ) [ ] > ) ) >
125128 publishers =
126- new ConcurrentDictionary < byte , ( Action < ReadOnlyMemory < ulong > > , Action < ( ulong , ResponseCode ) [ ] > ) > ( ) ;
129+ new ConcurrentDictionary < byte , ( string , ( Action < ReadOnlyMemory < ulong > > , Action < ( ulong , ResponseCode ) [ ] > )
130+ ) > ( ) ;
127131
128- internal readonly IDictionary < byte , ConsumerEvents > consumers =
129- new ConcurrentDictionary < byte , ConsumerEvents > ( ) ;
132+ internal readonly IDictionary < byte , ( string , ConsumerEvents ) > consumers =
133+ new ConcurrentDictionary < byte , ( string , ConsumerEvents ) > ( ) ;
130134
131135 private int publishCommandsSent ;
132136
@@ -312,7 +316,8 @@ public ValueTask<bool> Publish<T>(T msg) where T : struct, ICommand
312316
313317 try
314318 {
315- publishers . Add ( publisherId , ( confirmCallback , errorCallback ) ) ;
319+ publishers . Add ( publisherId , ( stream ,
320+ ( confirmCallback , errorCallback ) ) ) ;
316321 response = await Request < DeclarePublisherRequest , DeclarePublisherResponse > ( corr =>
317322 new DeclarePublisherRequest ( corr , publisherId , publisherRef , stream ) ) . ConfigureAwait ( false ) ;
318323 }
@@ -324,10 +329,9 @@ public ValueTask<bool> Publish<T>(T msg) where T : struct, ICommand
324329 if ( response . ResponseCode == ResponseCode . Ok )
325330 return ( publisherId , response ) ;
326331
327- // if the response code is not ok we need to remove the subscription
328332 // and close the connection if necessary.
329333 publishers . Remove ( publisherId ) ;
330- await MaybeClose ( "Create Publisher Exception" , stream , pool ) . ConfigureAwait ( false ) ;
334+ pool ? . MaybeClose ( ClientId , " Publisher creation failed" ) ;
331335 return ( publisherId , response ) ;
332336 }
333337
@@ -396,9 +400,10 @@ private byte IncrementEntityId()
396400 try
397401 {
398402 consumers . Add ( subscriptionId ,
399- new ConsumerEvents (
400- deliverHandler ,
401- consumerUpdateHandler ) ) ;
403+ ( config . Stream ,
404+ new ConsumerEvents (
405+ deliverHandler ,
406+ consumerUpdateHandler ) ) ) ;
402407
403408 response = await Request < SubscribeRequest , SubscribeResponse > ( corr =>
404409 new SubscribeRequest ( corr , subscriptionId , config . Stream , config . OffsetSpec , initialCredit ,
@@ -412,10 +417,8 @@ private byte IncrementEntityId()
412417 if ( response . ResponseCode == ResponseCode . Ok )
413418 return ( subscriptionId , response ) ;
414419
415- // if the response code is not ok we need to remove the subscription
416- // and close the connection if necessary.
417420 consumers . Remove ( subscriptionId ) ;
418- await MaybeClose ( "Create Consumer Exception" , config . Stream , config . Pool ) . ConfigureAwait ( false ) ;
421+ config . Pool . MaybeClose ( ClientId , "Subscription failed" ) ;
419422 return ( subscriptionId , response ) ;
420423 }
421424
@@ -518,7 +521,8 @@ private async Task HandleIncoming(Memory<byte> frameMemory)
518521 confirmFrames += 1 ;
519522 if ( publishers . TryGetValue ( confirm . PublisherId , out var publisherConf ) )
520523 {
521- var ( confirmCallback , _) = publisherConf ;
524+ var ( _, ( confirmCallback , _) ) = ( publisherConf ) ;
525+
522526 confirmCallback ( confirm . PublishingIds ) ;
523527 if ( MemoryMarshal . TryGetArray ( confirm . PublishingIds , out var confirmSegment ) )
524528 {
@@ -542,7 +546,8 @@ private async Task HandleIncoming(Memory<byte> frameMemory)
542546 Deliver . Read ( frame , out var deliver ) ;
543547 if ( consumers . TryGetValue ( deliver . SubscriptionId , out var consumerEvent ) )
544548 {
545- await consumerEvent . DeliverHandler ( deliver ) . ConfigureAwait ( false ) ;
549+ var ( _, deliverHandler ) = consumerEvent ;
550+ await deliverHandler . DeliverHandler ( deliver ) . ConfigureAwait ( false ) ;
546551 }
547552 else
548553 {
@@ -561,7 +566,7 @@ private async Task HandleIncoming(Memory<byte> frameMemory)
561566 PublishError . Read ( frame , out var error ) ;
562567 if ( publishers . TryGetValue ( error . PublisherId , out var publisher ) )
563568 {
564- var ( _, errorCallback ) = publisher ;
569+ var ( _, ( _ , errorCallback ) ) = publisher ;
565570 errorCallback ( error . PublishingErrors ) ;
566571 }
567572 else
@@ -588,7 +593,8 @@ private async Task HandleIncoming(Memory<byte> frameMemory)
588593 ConsumerUpdateQueryResponse . Read ( frame , out var consumerUpdateQueryResponse ) ;
589594 HandleCorrelatedResponse ( consumerUpdateQueryResponse ) ;
590595 var consumerEventsUpd = consumers [ consumerUpdateQueryResponse . SubscriptionId ] ;
591- var off = await consumerEventsUpd . ConsumerUpdateHandler ( consumerUpdateQueryResponse . IsActive )
596+ var consumer = consumerEventsUpd . Item2 ;
597+ var off = await consumer . ConsumerUpdateHandler ( consumerUpdateQueryResponse . IsActive )
592598 . ConfigureAwait ( false ) ;
593599 if ( off == null )
594600 {
@@ -736,14 +742,6 @@ private void InternalClose()
736742 IsClosed = true ;
737743 }
738744
739- private bool HasEntities ( )
740- {
741- lock ( Obj )
742- {
743- return publishers . Count > 0 || consumers . Count > 0 ;
744- }
745- }
746-
747745 private async ValueTask < bool > ConsumerUpdateResponse ( uint rCorrelationId , IOffsetType offsetSpecification )
748746 {
749747 return await Publish ( new ConsumerUpdateRequest ( rCorrelationId , offsetSpecification ) ) . ConfigureAwait ( false ) ;
@@ -759,6 +757,7 @@ public async Task<CloseResponse> Close(string reason)
759757 InternalClose ( ) ;
760758 try
761759 {
760+ connection . UpdateCloseStatus ( ConnectionClosedReason . Normal ) ;
762761 var result =
763762 await Request < CloseRequest , CloseResponse > ( corr => new CloseRequest ( corr , reason ) ,
764763 TimeSpan . FromSeconds ( 10 ) ) . ConfigureAwait ( false ) ;
@@ -794,32 +793,14 @@ public async Task<CloseResponse> Close(string reason)
794793 // Release will decrement the active ids for the connection
795794 // if the active ids are 0 the connection will be closed
796795
797- internal async Task < CloseResponse > MaybeClose ( string reason , string stream , ConnectionsPool pool )
796+ internal async Task < CloseResponse > MaybeClose ( string reason , ConnectionsPool pool )
798797 {
799798 await _poolSemaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
800799 try
801800 {
802- if ( ! HasEntities ( ) )
803- {
804- if ( ! string . IsNullOrEmpty ( ClientId ) )
805- {
806- _logger . LogInformation ( "Close connection for the {ClientId}" , ClientId ) ;
807- // the client can be closed in an unexpected way so we need to remove it from the pool
808- // so you will find pool.remove(ClientId) also to the disconnect event
809- pool . Remove ( ClientId ) ;
810- await Close ( reason ) . ConfigureAwait ( false ) ;
811- }
812- }
813- else
814- {
815- // we remove an id reference from the client
816- // in case there are still active ids from the client and the stream
817- if ( ! string . IsNullOrEmpty ( ClientId ) )
818- {
819- pool . Release ( ClientId , stream ) ;
820- }
821- }
822-
801+ // the client can be closed in an unexpected way so we need to remove it from the pool
802+ // so you will find pool.remove(ClientId) also to the disconnect event
803+ pool . MaybeClose ( ClientId , reason ) ;
823804 var result = new CloseResponse ( 0 , ResponseCode . Ok ) ;
824805 return result ;
825806 }
@@ -831,6 +812,16 @@ internal async Task<CloseResponse> MaybeClose(string reason, string stream, Conn
831812
832813 public string ClientId { get ; init ; }
833814
815+ public IDictionary < byte , ( string , ( Action < ReadOnlyMemory < ulong > > , Action < ( ulong , ResponseCode ) [ ] > ) ) > Publishers
816+ {
817+ get => publishers ;
818+ }
819+
820+ public IDictionary < byte , ( string , ConsumerEvents ) > Consumers
821+ {
822+ get => consumers ;
823+ }
824+
834825 public async ValueTask < QueryPublisherResponse > QueryPublisherSequence ( string publisherRef , string stream )
835826 {
836827 return await Request < QueryPublisherRequest , QueryPublisherResponse > ( corr =>
0 commit comments