You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
Assume stream composed of following:
Source constructed from IAsyncEnumerable<>.
Stream has a kill switch.
Sink is an actor that sends back back-pressure signal (using acknowledge message).
When:
Source is paused/interrupted because sink does not signal acknowledge message.
Stream is shut down via kill switch.
Then:
Enumerator provided by IAsyncEnumerable<> does not complete enumeration, leaving any resource allocated withing the enumerator not disposed. In my case this would be EF Core DbContext constructed via IDbContextFactory<>.
To Reproduce
usingAkka.Actor;usingAkka.Actor.Dsl;usingAkka.Streams;usingAkka.Streams.Dsl;usingSystem.Runtime.CompilerServices;constboolinterruptSinkActor=false;usingvarsystem=ActorSystem.Create("Streams");varsinkActorRef=system.ActorOf(act =>{act.ReceiveAny((message,context)=>{switch(message){caseintvalue:Console.WriteLine(value);if(interruptSinkActor&&value>50)Console.WriteLine("Interrupted. Press [Enter] to shutdown.");elsecontext.Sender.Tell(newAck());break;caseOnInit:context.Sender.Tell(newAck());break;caseComplete:break;}});});varstream=Source.From(()=>Enumerate(default)).ViaMaterialized(KillSwitches.Single<int>(),Keep.Right).ToMaterialized(Sink.ActorRefWithAck<int>(actorRef:sinkActorRef,onInitMessage:newOnInit(),ackMessage:newAck(),onCompleteMessage:newComplete()),Keep.Left);varkillSwitch=stream.Run(system);Console.ReadLine();killSwitch.Shutdown();awaitsystem.Terminate();Console.WriteLine("System terminated.");asyncstaticIAsyncEnumerable<int>Enumerate([EnumeratorCancellation]CancellationTokencancellationToken){awaitusingvarresource=newResource();foreach(variinEnumerable.Range(0,100)){awaitTask.Delay(1,cancellationToken).ConfigureAwait(false);yieldreturni;}}publicclassResource:IAsyncDisposable{publicValueTaskDisposeAsync(){Console.WriteLine("Enumerator completed and resource disposed");returnValueTask.CompletedTask;}}publicrecordclassOnInit();publicrecordclassAck();publicrecordclassComplete();
Links to working reproductions on Github / Gitlab are very much appreciated
Expected behavior
Async enumerator should be either disposed, or maybe awaited next via MoveNextAsync with cancellation triggered, so that enumerator is correctly completed. Resources allocated within enumerator are thus correctly disposed.
Actual behavior
Async enumerator is left uncompleted. Resources allocated within enumerator are not disposed.
@Aaronontheweb I peeked at this...
There's also a potential race in AsyncEnumerable stage's Read...
if (vtask.IsCompletedSuccessfully)
{
//fast success path
}
else if (vtask.IsCompleted)
{
//fast fail path
}
else
{
//slow path, handles both
}
The problem with this pattern is that in my experience it is possible for the task to complete successfully between the if and else if, which causes the else if path to fire even though it shouldn't. (To be clear, this takes a very good amount of load to consistently trigger, lost way too much sleep over it lol.)
On the plus side, getting rid of the fast fail path shouldn't be that harmful in the grand scheme of things.
Back to this specific issue, I think I see what's going on, we'll need to be a little clever in handling this but I think the logic from UnfoldResourceAsync will be a good starting reference point to fix.
Version Information
1.5.12
Akka, Akka.Streams
Describe the bug
Assume stream composed of following:
IAsyncEnumerable<>
.When:
Then:
IAsyncEnumerable<>
does not complete enumeration, leaving any resource allocated withing the enumerator not disposed. In my case this would be EF CoreDbContext
constructed viaIDbContextFactory<>
.To Reproduce
Links to working reproductions on Github / Gitlab are very much appreciated
Expected behavior
Async enumerator should be either disposed, or maybe awaited next via
MoveNextAsync
with cancellation triggered, so that enumerator is correctly completed. Resources allocated within enumerator are thus correctly disposed.Actual behavior
Async enumerator is left uncompleted. Resources allocated within enumerator are not disposed.
Screenshots
Interrupted enumerator:
Completed enumerator:
Environment
All environments are impacted.
Additional context
Disposal of the stream was removed previously by #6290, related to #6280.
The text was updated successfully, but these errors were encountered: