Added proper disposing to ServiceDescriptor.

Fixed ServiceDescriptor tests where cancellation didn't work.

Disposing currently awaited pipe terminates the task.
This commit is contained in:
Harrison Deng 2021-04-10 15:25:29 -05:00
parent a6f4d918cb
commit 911724627e

View File

@ -12,6 +12,7 @@ using System.Threading.Tasks;
using GameServiceWarden.Core.Games.Modules.Exceptions; using GameServiceWarden.Core.Games.Modules.Exceptions;
using GameServiceWarden.Core.Logging; using GameServiceWarden.Core.Logging;
using GameServiceWarden.API.Module; using GameServiceWarden.API.Module;
using System.Net.Sockets;
//TODO Update UML //TODO Update UML
namespace GameServiceWarden.Core.Games namespace GameServiceWarden.Core.Games
@ -40,6 +41,7 @@ namespace GameServiceWarden.Core.Games
private Task logUpdateTask; private Task logUpdateTask;
private Task acceptingTask; private Task acceptingTask;
private volatile CancellationTokenSource stopToken; private volatile CancellationTokenSource stopToken;
private NamedPipeServerStream acceptingPipe;
/// <summary> /// <summary>
/// Name of module this service uses. /// Name of module this service uses.
@ -110,9 +112,11 @@ namespace GameServiceWarden.Core.Games
if (!running) throw new InvalidOperationException("Service instance not running."); if (!running) throw new InvalidOperationException("Service instance not running.");
Logger.Log($"\"{ServiceName}\" is stopping."); Logger.Log($"\"{ServiceName}\" is stopping.");
service.ElegantShutdown(); service.ElegantShutdown();
stopToken.Cancel(); stopToken.Cancel(); // Doesn't work on Linux(?)
logSender.Close(); acceptingPipe.Close();
logReceiver.Close(); acceptingPipe.Dispose(); //Handles Linux case
logSender.Dispose(); //Makes sure logging client is disposed
logReceiver.Dispose(); //Closes receiver (Linux doesn't respond to cancellations, needed to dispose either way).
try try
{ {
if (!acceptingTask.Wait(TIMEOUT)) { if (!acceptingTask.Wait(TIMEOUT)) {
@ -121,7 +125,7 @@ namespace GameServiceWarden.Core.Games
} }
catch (AggregateException e) catch (AggregateException e)
{ {
e.Handle((exception) => exception is TaskCanceledException); e.Handle((exception) => exception is TaskCanceledException || exception is SocketException); //Task cancel for Windows, Socket for operation cancellation.
} }
try try
{ {
@ -131,10 +135,12 @@ namespace GameServiceWarden.Core.Games
} }
catch (AggregateException e) catch (AggregateException e)
{ {
e.Handle((exception) => exception is TaskCanceledException); e.Handle((exception) => exception is TaskCanceledException || exception is SocketException); //Same as above.
}
foreach (NamedPipeServerStream pipe in logStreamListeners)
{
pipe.Dispose();
} }
logSender.Dispose();
logReceiver.Dispose();
logStreamListeners.Clear(); logStreamListeners.Clear();
stopToken.Dispose(); stopToken.Dispose();
} }
@ -206,6 +212,7 @@ namespace GameServiceWarden.Core.Games
while (running) while (running)
{ {
NamedPipeServerStream pipe = new NamedPipeServerStream(ServiceLogPipeName, PipeDirection.Out, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); NamedPipeServerStream pipe = new NamedPipeServerStream(ServiceLogPipeName, PipeDirection.Out, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
acceptingPipe = pipe;
await pipe.WaitForConnectionAsync(stopToken.Token); await pipe.WaitForConnectionAsync(stopToken.Token);
Logger.Log($"A log listener has connected. Currently broadcasting to {logStreamListeners.Count + 1} listener(s).", LogLevel.DEBUG); Logger.Log($"A log listener has connected. Currently broadcasting to {logStreamListeners.Count + 1} listener(s).", LogLevel.DEBUG);
logStreamListeners.Push(pipe); logStreamListeners.Push(pipe);