1- using System . Diagnostics ;
21using System . Diagnostics . CodeAnalysis ;
32using Immediate . Handlers . Shared ;
43using Microsoft . Extensions . Caching . Memory ;
@@ -128,20 +127,8 @@ Owned<IHandler<TRequest, TResponse>> handler
128127 private TaskCompletionSource < TResponse > ? _responseSource ;
129128 private readonly Lock _lock = new ( ) ;
130129
131- public async ValueTask < TResponse > GetValue ( CancellationToken cancellationToken )
132- {
133- try
134- {
135- return await GetHandlerTask ( ) . WaitAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
136- }
137- catch ( OperationCanceledException ) when (
138- ! cancellationToken . IsCancellationRequested
139- && _responseSource ? . Task is { IsCompletedSuccessfully : true } task
140- )
141- {
142- return await task . ConfigureAwait ( false ) ;
143- }
144- }
130+ public async ValueTask < TResponse > GetValue ( CancellationToken cancellationToken ) =>
131+ await GetHandlerTask ( ) . WaitAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
145132
146133 [ SuppressMessage ( "Maintainability" , "CA1508:Avoid dead conditional code" , Justification = "Double-checked lock pattern" ) ]
147134 private Task < TResponse > GetHandlerTask ( )
@@ -154,43 +141,57 @@ private Task<TResponse> GetHandlerTask()
154141 if ( _responseSource is not null )
155142 return _responseSource . Task ;
156143
157- _tokenSource = new ( ) ;
158- _responseSource = new TaskCompletionSource < TResponse > ( ) ;
144+ var ts = _tokenSource = new ( ) ;
145+ _responseSource = new ( ) ;
159146
160- return Task . Run ( ( ) => RunHandler ( _tokenSource , _responseSource ) ) ;
147+ return Task . Run ( ( ) => RunHandler ( ts ) ) ;
161148 }
162149 }
163150
164- private async Task < TResponse > RunHandler (
165- CancellationTokenSource tokenSource ,
166- TaskCompletionSource < TResponse > responseSource
167- )
151+ private async Task < TResponse > RunHandler ( CancellationTokenSource tokenSource )
168152 {
169- try
153+ while ( true )
170154 {
171- var scope = handler . GetScope ( ) ;
155+ if ( _responseSource ? . Task is { IsCompletedSuccessfully : true } task )
156+ return await task . ConfigureAwait ( false ) ;
172157
173- await using ( scope . ConfigureAwait ( false ) )
158+ try
174159 {
175- var response = await scope . Service
176- . HandleAsync (
177- request ,
178- tokenSource . Token
179- )
180- . ConfigureAwait ( false ) ;
181-
182- lock ( _lock )
183- {
184- Debug . Assert ( _responseSource == responseSource ) ;
185- responseSource . SetResult ( response ) ;
160+ var token = tokenSource . Token ;
161+ var scope = handler . GetScope ( ) ;
186162
187- return response ;
163+ await using ( scope . ConfigureAwait ( false ) )
164+ {
165+ var response = await scope . Service
166+ . HandleAsync (
167+ request ,
168+ token
169+ )
170+ . ConfigureAwait ( false ) ;
171+
172+ lock ( _lock )
173+ {
174+ if ( ! token . IsCancellationRequested )
175+ {
176+ var rs = _responseSource ??= new ( ) ;
177+ rs . SetResult ( response ) ;
178+
179+ return response ;
180+ }
181+ }
188182 }
189183 }
190- }
191- catch ( OperationCanceledException ) when ( _responseSource is not null )
192- {
193- return await _responseSource . Task . ConfigureAwait ( false ) ;
184+ catch ( OperationCanceledException ) when ( tokenSource . IsCancellationRequested )
185+ {
186+ }
187+
188+ lock ( _lock )
189+ {
190+ if ( _tokenSource is null or { IsCancellationRequested : true } )
191+ _tokenSource = new ( ) ;
192+
193+ tokenSource = _tokenSource ;
194+ }
194195 }
195196 }
196197
@@ -201,6 +202,7 @@ public void SetValue(TResponse response)
201202 _responseSource = new TaskCompletionSource < TResponse > ( ) ;
202203 _responseSource . SetResult ( response ) ;
203204 _tokenSource ? . Cancel ( ) ;
205+ _tokenSource = null ;
204206 }
205207 }
206208
@@ -210,6 +212,7 @@ public void RemoveValue()
210212 {
211213 _responseSource = null ;
212214 _tokenSource ? . Cancel ( ) ;
215+ _tokenSource = null ;
213216 }
214217 }
215218 }
0 commit comments