18
18
using Neuroglia . AsyncApi . IO ;
19
19
using Neuroglia . AsyncApi . v3 ;
20
20
using Neuroglia . Data . Expressions ;
21
+ using System . Threading ;
21
22
22
23
namespace Synapse . Runner . Services . Executors ;
23
24
@@ -94,6 +95,11 @@ public class AsyncApiCallExecutor(IServiceProvider serviceProvider, ILogger<Asyn
94
95
/// </summary>
95
96
protected uint ? Offset { get ; set ; }
96
97
98
+ /// <summary>
99
+ /// Gets/sets a boolean indicating whether or not to keep consuming incoming messages
100
+ /// </summary>
101
+ protected bool KeepConsume { get ; set ; } = true ;
102
+
97
103
/// <summary>
98
104
/// Gets the path for the specified message
99
105
/// </summary>
@@ -234,7 +240,7 @@ protected virtual async Task DoExecuteSubscribeOperationAsync(CancellationToken
234
240
if ( this . AsyncApi . Subscription == null ) throw new NullReferenceException ( "The 'subscription' must be set when performing an AsyncAPI v3 subscribe operation" ) ;
235
241
await using var asyncApiClient = this . AsyncApiClientFactory . CreateFor ( this . Document ) ;
236
242
var parameters = new AsyncApiSubscribeOperationParameters ( this . Operation . Key , this . AsyncApi . Server , this . AsyncApi . Protocol ) ;
237
- await using var result = await asyncApiClient . SubscribeAsync ( parameters , cancellationToken ) . ConfigureAwait ( false ) ;
243
+ var result = await asyncApiClient . SubscribeAsync ( parameters , cancellationToken ) . ConfigureAwait ( false ) ;
238
244
if ( ! result . IsSuccessful ) throw new Exception ( "Failed to execute the AsyncAPI subscribe operation" ) ;
239
245
if ( result . Messages == null )
240
246
{
@@ -244,24 +250,24 @@ protected virtual async Task DoExecuteSubscribeOperationAsync(CancellationToken
244
250
var observable = result . Messages ;
245
251
if ( this . AsyncApi . Subscription . Consume . For != null ) observable = observable . TakeUntil ( Observable . Timer ( this . AsyncApi . Subscription . Consume . For . ToTimeSpan ( ) ) ) ;
246
252
if ( this . AsyncApi . Subscription . Consume . Amount . HasValue ) observable = observable . Take ( this . AsyncApi . Subscription . Consume . Amount . Value ) ;
247
- else if ( ! string . IsNullOrWhiteSpace ( this . AsyncApi . Subscription . Consume . While ) ) observable = observable . Select ( message => Observable . FromAsync ( async ( ) =>
248
- {
249
- var keepGoing = await this . Task . Workflow . Expressions . EvaluateConditionAsync ( this . AsyncApi . Subscription . Consume . While , this . Task . Input ! , this . GetExpressionEvaluationArguments ( ) , cancellationToken ) . ConfigureAwait ( false ) ;
250
- return ( message , keepGoing ) ;
251
- } ) ) . Concat ( ) . TakeWhile ( i => i . keepGoing ) . Select ( i => i . message ) ;
252
- else if ( ! string . IsNullOrWhiteSpace ( this . AsyncApi . Subscription . Consume . Until ) ) observable = observable . Select ( message => Observable . FromAsync ( async ( ) =>
253
- {
254
- var keepGoing = ! ( await this . Task . Workflow . Expressions . EvaluateConditionAsync ( this . AsyncApi . Subscription . Consume . Until , this . Task . Input ! , this . GetExpressionEvaluationArguments ( ) , cancellationToken ) . ConfigureAwait ( false ) ) ;
255
- return ( message , keepGoing ) ;
256
- } ) ) . Concat ( ) . TakeWhile ( i => i . keepGoing ) . Select ( i => i . message ) ;
257
253
if ( this . AsyncApi . Subscription . Foreach == null )
258
254
{
259
- var messages = await observable . ToAsyncEnumerable ( ) . ToListAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
255
+ var messages = await observable . ToAsyncEnumerable ( ) . TakeWhileAwait ( async m =>
256
+ {
257
+ if ( ! string . IsNullOrWhiteSpace ( this . AsyncApi . Subscription . Consume . While ) ) return await this . Task . Workflow . Expressions . EvaluateConditionAsync ( this . AsyncApi . Subscription . Consume . While , this . Task . Input ! , this . GetExpressionEvaluationArguments ( ) , cancellationToken ) . ConfigureAwait ( false ) ;
258
+ if ( ! string . IsNullOrWhiteSpace ( this . AsyncApi . Subscription . Consume . Until ) ) return ! await this . Task . Workflow . Expressions . EvaluateConditionAsync ( this . AsyncApi . Subscription . Consume . Until , this . Task . Input ! , this . GetExpressionEvaluationArguments ( ) , cancellationToken ) . ConfigureAwait ( false ) ;
259
+ return true ;
260
+ } ) . ToListAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
260
261
await this . SetResultAsync ( messages , this . Task . Definition . Then , cancellationToken ) . ConfigureAwait ( false ) ;
261
262
}
262
263
else
263
264
{
264
- this . Subscription = observable . SubscribeAsync ( OnStreamingMessageAsync , OnStreamingErrorAsync , OnStreamingCompletedAsync ) ;
265
+ //todo: fix
266
+ this . Subscription = observable . TakeWhile ( _ => this . KeepConsume ) . SelectMany ( m =>
267
+ {
268
+ OnStreamingMessageAsync ( m ) . GetAwaiter ( ) . GetResult ( ) ;
269
+ return Observable . Return ( m ) ;
270
+ } ) . SubscribeAsync ( _ => System . Threading . Tasks . Task . CompletedTask , OnStreamingErrorAsync , OnStreamingCompletedAsync ) ;
265
271
}
266
272
}
267
273
@@ -274,6 +280,11 @@ protected virtual async Task OnStreamingMessageAsync(IAsyncApiMessage message)
274
280
{
275
281
if ( this . AsyncApi == null || this . Document == null || this . Operation . Value == null ) throw new InvalidOperationException ( "The executor must be initialized before execution" ) ;
276
282
if ( this . AsyncApi . Subscription == null ) throw new NullReferenceException ( "The 'subscription' must be set when performing an AsyncAPI v3 subscribe operation" ) ;
283
+ if ( ! string . IsNullOrWhiteSpace ( this . AsyncApi . Subscription . Consume . While ) && ! await this . Task . Workflow . Expressions . EvaluateConditionAsync ( this . AsyncApi . Subscription . Consume . While , this . Task . Input ! , this . GetExpressionEvaluationArguments ( ) , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) )
284
+ {
285
+ this . KeepConsume = false ;
286
+ return ;
287
+ }
277
288
if ( this . AsyncApi . Subscription . Foreach ? . Do != null )
278
289
{
279
290
var taskDefinition = new DoTaskDefinition ( )
@@ -284,30 +295,36 @@ protected virtual async Task OnStreamingMessageAsync(IAsyncApiMessage message)
284
295
new ( SynapseDefaults . Tasks . Metadata . PathPrefix . Name , false )
285
296
]
286
297
} ;
287
- var arguments = this . GetExpressionEvaluationArguments ( ) ;
288
298
var messageData = message as object ;
299
+ var offset = this . Offset ?? 0 ;
300
+ if ( ! this . Offset . HasValue ) this . Offset = 0 ;
301
+ var arguments = this . GetExpressionEvaluationArguments ( ) ;
302
+ arguments ??= new Dictionary < string , object > ( ) ;
303
+ arguments [ this . AsyncApi . Subscription . Foreach . Item ?? RuntimeExpressions . Arguments . Each ] = messageData ! ;
304
+ arguments [ this . AsyncApi . Subscription . Foreach . At ?? RuntimeExpressions . Arguments . Index ] = offset ;
289
305
if ( this . AsyncApi . Subscription . Foreach . Output ? . As is string fromExpression ) messageData = await this . Task . Workflow . Expressions . EvaluateAsync < object > ( fromExpression , messageData ?? new ( ) , arguments , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
290
- else if ( this . AsyncApi . Subscription . Foreach . Output ? . As != null ) messageData = await this . Task . Workflow . Expressions . EvaluateAsync < object > ( this . AsyncApi . Subscription . Foreach . Output . As , messageData ?? new ( ) , arguments , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
306
+ else if ( this . AsyncApi . Subscription . Foreach . Output ? . As != null ) messageData = await this . Task . Workflow . Expressions . EvaluateAsync < object > ( this . AsyncApi . Subscription . Foreach . Output . As ! , messageData ?? new ( ) , arguments , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
291
307
if ( this . AsyncApi . Subscription . Foreach . Export ? . As is string toExpression )
292
308
{
293
309
var context = ( await this . Task . Workflow . Expressions . EvaluateAsync < IDictionary < string , object > > ( toExpression , messageData ?? new ( ) , arguments , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ) ! ;
294
310
await this . Task . SetContextDataAsync ( context , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
295
311
}
296
312
else if ( this . AsyncApi . Subscription . Foreach . Export ? . As != null )
297
313
{
298
- var context = ( await this . Task . Workflow . Expressions . EvaluateAsync < IDictionary < string , object > > ( this . AsyncApi . Subscription . Foreach . Export . As , messageData ?? new ( ) , arguments , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ) ! ;
314
+ var context = ( await this . Task . Workflow . Expressions . EvaluateAsync < IDictionary < string , object > > ( this . AsyncApi . Subscription . Foreach . Export . As ! , messageData ?? new ( ) , arguments , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ) ! ;
299
315
await this . Task . SetContextDataAsync ( context , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
300
316
}
301
- var offset = this . Offset ?? 0 ;
302
- if ( ! this . Offset . HasValue ) this . Offset = 0 ;
303
- arguments ??= new Dictionary < string , object > ( ) ;
304
- arguments [ this . AsyncApi . Subscription . Foreach . Item ?? RuntimeExpressions . Arguments . Each ] = messageData ! ;
305
- arguments [ this . AsyncApi . Subscription . Foreach . At ?? RuntimeExpressions . Arguments . Index ] = offset ;
306
317
var task = await this . Task . Workflow . CreateTaskAsync ( taskDefinition , this . GetPathFor ( offset ) , this . Task . Input , null , this . Task , false , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
307
318
var taskExecutor = await this . CreateTaskExecutorAsync ( task , taskDefinition , this . Task . ContextData , arguments , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
308
319
await taskExecutor . ExecuteAsync ( this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
320
+ if ( this . Task . ContextData != taskExecutor . Task . ContextData ) await this . Task . SetContextDataAsync ( taskExecutor . Task . ContextData , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) ;
309
321
this . Offset ++ ;
310
322
}
323
+ if ( ! string . IsNullOrWhiteSpace ( this . AsyncApi . Subscription . Consume . Until ) && await this . Task . Workflow . Expressions . EvaluateConditionAsync ( this . AsyncApi . Subscription . Consume . Until , this . Task . Input ! , this . GetExpressionEvaluationArguments ( ) , this . CancellationTokenSource ! . Token ) . ConfigureAwait ( false ) )
324
+ {
325
+ this . KeepConsume = false ;
326
+ return ;
327
+ }
311
328
}
312
329
313
330
/// <summary>
0 commit comments