Skip to content

Commit d88dd36

Browse files
Merge branch 'dev' into test/redeployment-determinism
2 parents 17793bd + a918393 commit d88dd36

1 file changed

Lines changed: 15 additions & 2 deletions

File tree

src/core/Akka.Remote/Transport/TransportAdapters.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -550,8 +550,21 @@ protected override void InterceptAssociate(Address remoteAddress, TaskCompletion
550550
public override Task<bool> Shutdown()
551551
{
552552
var stopTask = manager.GracefulStop((RARP.For(System).Provider).RemoteSettings.FlushWait);
553-
var transportStopTask = WrappedTransport.Shutdown();
554-
return Task.WhenAll(stopTask, transportStopTask).ContinueWith(x => x.IsCompleted && !(x.IsFaulted || x.IsCanceled), TaskContinuationOptions.ExecuteSynchronously);
553+
554+
// Sequence the wrapped-transport teardown AFTER the manager (and its child association
555+
// actors) have stopped. Those children write the graceful Disassociate PDU as part of
556+
// their own shutdown; running WrappedTransport.Shutdown() concurrently (as this used to)
557+
// let the underlying transport force-close the channel out from under a not-yet-flushed
558+
// Disassociate. Peers then kept a "zombie" association until the transport failure
559+
// detector tripped (up to acceptable-heartbeat-pause, 120s by default). The manager stop
560+
// is bounded by flush-wait-on-shutdown, and the wrapped transport is torn down regardless
561+
// of whether the manager stopped cleanly, so shutdown can never hang on this ordering.
562+
var transportStopTask = stopTask.ContinueWith(_ => WrappedTransport.Shutdown(),
563+
TaskContinuationOptions.ExecuteSynchronously).Unwrap();
564+
565+
return Task.WhenAll(stopTask, transportStopTask)
566+
.ContinueWith(x => x.IsCompleted && !(x.IsFaulted || x.IsCanceled),
567+
TaskContinuationOptions.ExecuteSynchronously);
555568
}
556569
}
557570

0 commit comments

Comments
 (0)