22
22
using Akka . Streams . Util ;
23
23
using Akka . Util ;
24
24
using Akka . Util . Internal ;
25
+ using Debug = System . Diagnostics . Debug ;
25
26
using Decider = Akka . Streams . Supervision . Decider ;
26
27
using Directive = Akka . Streams . Supervision . Directive ;
27
28
@@ -2512,61 +2513,47 @@ public Expand(Func<TIn, IEnumerator<TOut>> extrapolate)
2512
2513
/// </returns>
2513
2514
public override string ToString ( ) => "Expand" ;
2514
2515
}
2516
+
2517
+ #nullable enable
2515
2518
2516
2519
/// <summary>
2517
2520
/// INTERNAL API
2518
2521
/// </summary>
2519
- /// <typeparam name="TIn">TBD</typeparam>
2520
- /// <typeparam name="TOut">TBD</typeparam>
2521
2522
[ InternalApi ]
2522
2523
public sealed class SelectAsync < TIn , TOut > : GraphStage < FlowShape < TIn , TOut > >
2523
2524
{
2524
2525
#region internal classes
2525
2526
2526
2527
private sealed class Logic : InAndOutGraphStageLogic
2527
2528
{
2528
- private class Holder < T >
2529
+ private sealed class Holder < T > ( object ? message , Result < T > element )
2529
2530
{
2530
- private readonly Action < Holder < T > > _callback ;
2531
-
2532
- public Holder ( object message , Result < T > element , Action < Holder < T > > callback )
2533
- {
2534
- _callback = callback ;
2535
- Message = message ;
2536
- Element = element ;
2537
- }
2538
-
2539
- public Result < T > Element { get ; private set ; }
2540
- public object Message { get ; }
2531
+ public object ? Message { get ; private set ; } = message ;
2532
+
2533
+ public Result < T > Element { get ; private set ; } = element ;
2541
2534
2542
2535
public void SetElement ( Result < T > result )
2543
2536
{
2544
2537
Element = result . IsSuccess && result . Value == null
2545
2538
? Result . Failure < T > ( ReactiveStreamsCompliance . ElementMustNotBeNullException )
2546
2539
: result ;
2547
2540
}
2548
-
2549
- public void Invoke ( Result < T > result )
2550
- {
2551
- SetElement ( result ) ;
2552
- _callback ( this ) ;
2553
- }
2554
2541
}
2555
2542
2556
2543
private static readonly Result < TOut > NotYetThere = Result . Failure < TOut > ( new Exception ( ) ) ;
2557
2544
2558
2545
private readonly SelectAsync < TIn , TOut > _stage ;
2559
2546
private readonly Decider _decider ;
2560
2547
private IBuffer < Holder < TOut > > _buffer ;
2561
- private readonly Action < Holder < TOut > > _taskCallback ;
2548
+ private readonly Action < ( Holder < TOut > , Result < TOut > ) > _taskCallback ;
2562
2549
2563
2550
public Logic ( Attributes inheritedAttributes , SelectAsync < TIn , TOut > stage ) : base ( stage . Shape )
2564
2551
{
2565
2552
_stage = stage ;
2566
- var attr = inheritedAttributes . GetAttribute < ActorAttributes . SupervisionStrategy > ( null ) ;
2553
+ var attr = inheritedAttributes . GetAttribute < ActorAttributes . SupervisionStrategy > ( ) ;
2567
2554
_decider = attr != null ? attr . Decider : Deciders . StoppingDecider ;
2568
2555
2569
- _taskCallback = GetAsyncCallback < Holder < TOut > > ( HolderCompleted ) ;
2556
+ _taskCallback = GetAsyncCallback < ( Holder < TOut > holder , Result < TOut > result ) > ( t => HolderCompleted ( t . holder , t . result ) ) ;
2570
2557
2571
2558
SetHandlers ( stage . In , stage . Out , this ) ;
2572
2559
}
@@ -2577,19 +2564,33 @@ public override void OnPush()
2577
2564
try
2578
2565
{
2579
2566
var task = _stage . _mapFunc ( message ) ;
2580
- var holder = new Holder < TOut > ( message , NotYetThere , _taskCallback ) ;
2567
+ var holder = new Holder < TOut > ( message , NotYetThere ) ;
2581
2568
_buffer . Enqueue ( holder ) ;
2582
2569
2583
2570
// We dispatch the task if it's ready to optimize away
2584
2571
// scheduling it to an execution context
2585
2572
if ( task . IsCompleted )
2586
2573
{
2587
- holder . SetElement ( Result . FromTask ( task ) ) ;
2588
- HolderCompleted ( holder ) ;
2574
+ HolderCompleted ( holder , Result . FromTask ( task ) ) ;
2589
2575
}
2590
2576
else
2591
- task . ContinueWith ( t => holder . Invoke ( Result . FromTask ( t ) ) ,
2592
- TaskContinuationOptions . ExecuteSynchronously ) ;
2577
+ {
2578
+ async Task WaitForTask ( )
2579
+ {
2580
+ try
2581
+ {
2582
+ var result = Result . Success ( await task ) ;
2583
+ _taskCallback ( ( holder , result ) ) ;
2584
+ }
2585
+ catch ( Exception ex ) {
2586
+ var result = Result . Failure < TOut > ( ex ) ;
2587
+ _taskCallback ( ( holder , result ) ) ;
2588
+ }
2589
+ }
2590
+
2591
+ _ = WaitForTask ( ) ;
2592
+ }
2593
+
2593
2594
}
2594
2595
catch ( Exception e )
2595
2596
{
@@ -2606,7 +2607,7 @@ public override void OnPush()
2606
2607
break ;
2607
2608
2608
2609
default :
2609
- throw new AggregateException ( $ "Unknown SupervisionStrategy directive: { strategy } ", e ) ;
2610
+ throw new ArgumentOutOfRangeException ( $ "Unknown SupervisionStrategy directive: { strategy } ", e ) ;
2610
2611
}
2611
2612
}
2612
2613
if ( Todo < _stage . _parallelism && ! HasBeenPulled ( _stage . In ) )
@@ -2663,12 +2664,12 @@ private void PushOne()
2663
2664
break ;
2664
2665
2665
2666
default :
2666
- throw new AggregateException ( $ "Unknown SupervisionStrategy directive: { strategy } ", result . Exception ) ;
2667
+ throw new ArgumentOutOfRangeException ( $ "Unknown SupervisionStrategy directive: { strategy } ", result . Exception ) ;
2667
2668
}
2668
2669
continue ;
2669
2670
}
2670
2671
2671
- Push ( _stage . Out , result . Value ) ;
2672
+ Push ( _stage . Out ! , result . Value ) ;
2672
2673
if ( Todo < _stage . _parallelism && ! HasBeenPulled ( inlet ) )
2673
2674
TryPull ( inlet ) ;
2674
2675
}
@@ -2677,17 +2678,18 @@ private void PushOne()
2677
2678
}
2678
2679
}
2679
2680
2680
- private void HolderCompleted ( Holder < TOut > holder )
2681
+ private void HolderCompleted ( Holder < TOut > holder , Result < TOut > result )
2681
2682
{
2682
- var element = holder . Element ;
2683
- if ( element . IsSuccess )
2683
+ // we may not be at the front of the line right now, so save the result for later
2684
+ holder . SetElement ( result ) ;
2685
+ if ( result . IsSuccess )
2684
2686
{
2685
2687
if ( IsAvailable ( _stage . Out ) )
2686
2688
PushOne ( ) ;
2687
2689
return ;
2688
2690
}
2689
2691
2690
- var exception = element . Exception ;
2692
+ var exception = result . Exception ;
2691
2693
var strategy = _decider ( exception ) ;
2692
2694
Log . Error ( exception , "An exception occured inside SelectAsync while executing Task. Supervision strategy: {0}" , strategy ) ;
2693
2695
switch ( strategy )
@@ -2703,7 +2705,7 @@ private void HolderCompleted(Holder<TOut> holder)
2703
2705
break ;
2704
2706
2705
2707
default :
2706
- throw new AggregateException ( $ "Unknown SupervisionStrategy directive: { strategy } ", exception ) ;
2708
+ throw new ArgumentOutOfRangeException ( $ "Unknown SupervisionStrategy directive: { strategy } ", exception ) ;
2707
2709
}
2708
2710
}
2709
2711
@@ -2758,8 +2760,6 @@ protected override GraphStageLogic CreateLogic(Attributes inheritedAttributes)
2758
2760
/// <summary>
2759
2761
/// INTERNAL API
2760
2762
/// </summary>
2761
- /// <typeparam name="TIn">TBD</typeparam>
2762
- /// <typeparam name="TOut">TBD</typeparam>
2763
2763
[ InternalApi ]
2764
2764
public sealed class SelectAsyncUnordered < TIn , TOut > : GraphStage < FlowShape < TIn , TOut > >
2765
2765
{
@@ -2904,6 +2904,8 @@ public SelectAsyncUnordered(int parallelism, Func<TIn, Task<TOut>> mapFunc)
2904
2904
protected override GraphStageLogic CreateLogic ( Attributes inheritedAttributes )
2905
2905
=> new Logic ( inheritedAttributes , this ) ;
2906
2906
}
2907
+
2908
+ #nullable disable
2907
2909
2908
2910
/// <summary>
2909
2911
/// INTERNAL API
0 commit comments