@@ -21,11 +21,11 @@ internal class Writer<TValue> : IWriter<TValue>
2121 private readonly WriterConfig _config ;
2222 private readonly ILogger < Writer < TValue > > _logger ;
2323 private readonly ISerializer < TValue > _serializer ;
24- private readonly GrpcRequestSettings _writerGrpcRequestSettings ;
24+ private readonly GrpcRequestSettings _writerGrpcRequestSettings = new ( ) ;
2525 private readonly ConcurrentQueue < MessageSending > _toSendBuffer = new ( ) ;
2626 private readonly ConcurrentQueue < MessageSending > _inFlightMessages = new ( ) ;
2727 private readonly CancellationTokenSource _disposeCts = new ( ) ;
28- private readonly SemaphoreSlim _clearInFlightMessagesSemaphoreSlim = new ( 1 ) ;
28+ private readonly SemaphoreSlim _sendInFlightMessagesSemaphoreSlim = new ( 1 ) ;
2929
3030 private volatile TaskCompletionSource _tcsWakeUp = new ( ) ;
3131 private volatile TaskCompletionSource _tcsBufferAvailableEvent = new ( ) ;
@@ -39,7 +39,6 @@ internal Writer(IDriver driver, WriterConfig config, ISerializer<TValue> seriali
3939 _logger = driver . LoggerFactory . CreateLogger < Writer < TValue > > ( ) ;
4040 _serializer = serializer ;
4141 _limitBufferMaxSize = config . BufferMaxSize ;
42- _writerGrpcRequestSettings = new GrpcRequestSettings { CancellationToken = _disposeCts . Token } ;
4342
4443 StartWriteWorker ( ) ;
4544 }
@@ -95,7 +94,9 @@ public async Task<WriteResult> WriteAsync(Message<TValue> message, CancellationT
9594 if ( Interlocked . CompareExchange ( ref _limitBufferMaxSize ,
9695 curLimitBufferSize - data . Length , curLimitBufferSize ) == curLimitBufferSize )
9796 {
98- _toSendBuffer . Enqueue ( new MessageSending ( messageData , tcs ) ) ;
97+ _toSendBuffer . Enqueue (
98+ new MessageSending ( messageData , tcs , writerDisposedCancellationTokenRegistration )
99+ ) ;
99100 WakeUpWorker ( ) ;
100101
101102 break ;
@@ -162,7 +163,7 @@ private async void StartWriteWorker()
162163 continue ;
163164 }
164165
165- await _clearInFlightMessagesSemaphoreSlim . WaitAsync ( _disposeCts . Token ) ;
166+ await _sendInFlightMessagesSemaphoreSlim . WaitAsync ( _disposeCts . Token ) ;
166167 try
167168 {
168169 if ( _session . IsActive )
@@ -172,7 +173,7 @@ private async void StartWriteWorker()
172173 }
173174 finally
174175 {
175- _clearInFlightMessagesSemaphoreSlim . Release ( ) ;
176+ _sendInFlightMessagesSemaphoreSlim . Release ( ) ;
176177 }
177178 }
178179 }
@@ -193,7 +194,7 @@ private async Task Initialize()
193194
194195 try
195196 {
196- if ( _disposeCts . IsCancellationRequested )
197+ if ( _disposeCts . IsCancellationRequested && _inFlightMessages . IsEmpty )
197198 {
198199 _logger . LogWarning ( "Initialize writer is canceled because it has been disposed" ) ;
199200
@@ -267,7 +268,7 @@ private async Task Initialize()
267268 return ;
268269 }
269270
270- await _clearInFlightMessagesSemaphoreSlim . WaitAsync ( _disposeCts . Token ) ;
271+ await _sendInFlightMessagesSemaphoreSlim . WaitAsync ( _disposeCts . Token ) ;
271272 try
272273 {
273274 var copyInFlightMessages = new ConcurrentQueue < MessageSending > ( ) ;
@@ -315,7 +316,7 @@ private async Task Initialize()
315316 }
316317 finally
317318 {
318- _clearInFlightMessagesSemaphoreSlim . Release ( ) ;
319+ _sendInFlightMessagesSemaphoreSlim . Release ( ) ;
319320 }
320321 }
321322 catch ( Driver . TransportException e )
@@ -330,17 +331,42 @@ private async Task Initialize()
330331 }
331332 }
332333
333- public void Dispose ( )
334+ public async ValueTask DisposeAsync ( )
334335 {
335- _disposeCts . Cancel ( ) ;
336+ await _sendInFlightMessagesSemaphoreSlim . WaitAsync ( ) ;
337+ try
338+ {
339+ _disposeCts . Dispose ( ) ;
340+ }
341+ finally
342+ {
343+ _sendInFlightMessagesSemaphoreSlim . Release ( ) ;
344+ }
336345
337- _session = new NotStartedWriterSession ( "Writer is disposed" ) ;
346+ // wait all messages
347+ foreach ( var inFlightMessage in _inFlightMessages )
348+ {
349+ try
350+ {
351+ await inFlightMessage . Tcs . Task ;
352+ }
353+ catch ( Exception e )
354+ {
355+ _logger . LogWarning ( e , "Failed in flight message" ) ;
356+ }
357+ }
358+
359+ await _session . DisposeAsync ( ) ;
338360 }
339361}
340362
341- internal record MessageSending ( MessageData MessageData , TaskCompletionSource < WriteResult > Tcs ) ;
363+ internal record MessageSending (
364+ MessageData MessageData ,
365+ TaskCompletionSource < WriteResult > Tcs ,
366+ CancellationTokenRegistration DisposedCtr
367+ ) ;
342368
343- internal interface IWriteSession
369+ internal interface IWriteSession : IAsyncDisposable
344370{
345371 Task Write ( ConcurrentQueue < MessageSending > toSendBuffer ) ;
346372
@@ -372,6 +398,11 @@ public Task Write(ConcurrentQueue<MessageSending> toSendBuffer)
372398 }
373399
374400 public bool IsActive => true ;
401+
402+ public ValueTask DisposeAsync ( )
403+ {
404+ return ValueTask . CompletedTask ;
405+ }
375406}
376407
377408internal class DummyWriterSession : IWriteSession
@@ -388,6 +419,11 @@ public Task Write(ConcurrentQueue<MessageSending> toSendBuffer)
388419 }
389420
390421 public bool IsActive => false ;
422+
423+ public ValueTask DisposeAsync ( )
424+ {
425+ return ValueTask . CompletedTask ;
426+ }
391427}
392428
393429internal class WriterSession : TopicSession < MessageFromClient , MessageFromServer > , IWriteSession
@@ -437,6 +473,8 @@ public async Task Write(ConcurrentQueue<MessageSending> toSendBuffer)
437473 continue ;
438474 }
439475
476+ sendData . DisposedCtr . Unregister ( ) ;
477+
440478 var messageData = sendData . MessageData ;
441479
442480 if ( messageData . SeqNo == default )
0 commit comments