[c# epoxy] Clean up unstarted EpoxyConnections
If an EpoxyListener or EpoxyTransport is shutdown between creation of a EpoxyConnection, but before the connection was started, calling StopAsync() on the connection would never complete, as the connection loop needed to run to transition the connection to Disconnected. Now, EpoxyConnection.StopAsync() can be called before the connection has been started to clean up the network resources.
This commit is contained in:
Родитель
059a593f5f
Коммит
9b070671dd
|
@ -832,9 +832,25 @@ namespace Bond.Comm.Epoxy
|
|||
public override Task StopAsync()
|
||||
{
|
||||
EnsureCorrectState(State.All);
|
||||
|
||||
shutdownTokenSource.Cancel();
|
||||
networkStream.Shutdown();
|
||||
|
||||
if (state == State.Created)
|
||||
{
|
||||
// If the connection has yet to be started, we cannot rely on
|
||||
// the main loop to advance states, so we just transition to
|
||||
// Disconnected and signal that we've stopped.
|
||||
//
|
||||
// It's OK to directly transition to Disconnected. No one else
|
||||
// is going to call StartAsync() on this connection, as the
|
||||
// thread that is responsible for calling StartAsync() is the
|
||||
// same thread that has decided to abandon the connection
|
||||
// BEFORE calling StartAsync().
|
||||
state = State.Disconnected;
|
||||
stopTask.TrySetResult(true);
|
||||
}
|
||||
|
||||
return stopTask.Task;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
namespace Bond.Comm.Epoxy
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
@ -191,14 +190,16 @@ namespace Bond.Comm.Epoxy
|
|||
logger,
|
||||
metrics);
|
||||
|
||||
// TODO
|
||||
// Handle a race condition: if the listener is shutdown after we've
|
||||
// accepted a connection, but before we've added it to this
|
||||
// collection, we need to clean up this connection on its own.
|
||||
// However, we haven't started the connection yet, so
|
||||
// EpoxyConnection.StopAsync() will never complete. For now, we're
|
||||
// just going to leak this connection.
|
||||
connections.Add(connection);
|
||||
try
|
||||
{
|
||||
connections.Add(connection);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
logger.Site().Debug("Listener was shutdown while accepting connection from {0}. Connection has been abandoned.", connection.RemoteEndPoint);
|
||||
await connection.StopAsync();
|
||||
throw;
|
||||
}
|
||||
|
||||
logger.Site().Debug("Setup server-side connection for {0}. Starting Epoxy handshake.", connection.RemoteEndPoint);
|
||||
await connection.StartAsync();
|
||||
|
|
|
@ -305,14 +305,7 @@ namespace Bond.Comm.Epoxy
|
|||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// TODO
|
||||
// Handle a race condition: if the transport is shutdown
|
||||
// after we've created this connection, but before we've
|
||||
// added it to this collection, we need to clean up this
|
||||
// connection on its own. However, we haven't started the
|
||||
// connection yet, so EpoxyConnection.StopAsync() will
|
||||
// never complete. For now, we're just going to leak this
|
||||
// connection.
|
||||
await connection.StopAsync();
|
||||
throw new InvalidOperationException("This EpoxyTransport has been stopped already.");
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче