Implement graceful worker shutdown
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using MxGateway.Contracts.Proto;
|
||||
@@ -188,6 +189,23 @@ public sealed class MxAccessSession : IDisposable
|
||||
MxAccessAdviceKind.Supervisory);
|
||||
}
|
||||
|
||||
public MxAccessShutdownResult ShutdownGracefully()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return new MxAccessShutdownResult(Array.Empty<MxAccessShutdownFailure>());
|
||||
}
|
||||
|
||||
List<MxAccessShutdownFailure> failures = new();
|
||||
|
||||
CleanupAdviceHandles(failures);
|
||||
CleanupItemHandles(failures);
|
||||
CleanupServerHandles(failures);
|
||||
DisposeCore(failures);
|
||||
|
||||
return new MxAccessShutdownResult(failures);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposed)
|
||||
@@ -195,11 +213,112 @@ public sealed class MxAccessSession : IDisposable
|
||||
return;
|
||||
}
|
||||
|
||||
eventSink.Detach();
|
||||
DisposeCore(failures: null);
|
||||
}
|
||||
|
||||
if (Marshal.IsComObject(mxAccessComObject))
|
||||
private void CleanupAdviceHandles(ICollection<MxAccessShutdownFailure> failures)
|
||||
{
|
||||
HashSet<long> cleanedPairs = new();
|
||||
foreach (RegisteredAdviceHandle adviceHandle in handleRegistry.AdviceHandles)
|
||||
{
|
||||
Marshal.FinalReleaseComObject(mxAccessComObject);
|
||||
long key = CreateItemKey(adviceHandle.ServerHandle, adviceHandle.ItemHandle);
|
||||
if (!cleanedPairs.Add(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mxAccessServer.UnAdvise(adviceHandle.ServerHandle, adviceHandle.ItemHandle);
|
||||
handleRegistry.RemoveAdviceHandles(adviceHandle.ServerHandle, adviceHandle.ItemHandle);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
failures.Add(new MxAccessShutdownFailure(
|
||||
nameof(UnAdvise),
|
||||
adviceHandle.ServerHandle,
|
||||
adviceHandle.ItemHandle,
|
||||
exception));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupItemHandles(ICollection<MxAccessShutdownFailure> failures)
|
||||
{
|
||||
foreach (RegisteredItemHandle itemHandle in handleRegistry.ItemHandles)
|
||||
{
|
||||
try
|
||||
{
|
||||
mxAccessServer.RemoveItem(itemHandle.ServerHandle, itemHandle.ItemHandle);
|
||||
handleRegistry.RemoveItemHandle(itemHandle.ServerHandle, itemHandle.ItemHandle);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
failures.Add(new MxAccessShutdownFailure(
|
||||
nameof(RemoveItem),
|
||||
itemHandle.ServerHandle,
|
||||
itemHandle.ItemHandle,
|
||||
exception));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupServerHandles(ICollection<MxAccessShutdownFailure> failures)
|
||||
{
|
||||
foreach (RegisteredServerHandle serverHandle in handleRegistry.ServerHandles)
|
||||
{
|
||||
try
|
||||
{
|
||||
mxAccessServer.Unregister(serverHandle.ServerHandle);
|
||||
handleRegistry.UnregisterServerHandle(serverHandle.ServerHandle);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
failures.Add(new MxAccessShutdownFailure(
|
||||
nameof(Unregister),
|
||||
serverHandle.ServerHandle,
|
||||
itemHandle: null,
|
||||
exception));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long CreateItemKey(
|
||||
int serverHandle,
|
||||
int itemHandle)
|
||||
{
|
||||
return ((long)serverHandle << 32) | (uint)itemHandle;
|
||||
}
|
||||
|
||||
private void DisposeCore(ICollection<MxAccessShutdownFailure>? failures)
|
||||
{
|
||||
try
|
||||
{
|
||||
eventSink.Detach();
|
||||
}
|
||||
catch (Exception exception) when (failures is not null)
|
||||
{
|
||||
failures.Add(new MxAccessShutdownFailure(
|
||||
"DetachEvents",
|
||||
serverHandle: null,
|
||||
itemHandle: null,
|
||||
exception));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (Marshal.IsComObject(mxAccessComObject))
|
||||
{
|
||||
Marshal.FinalReleaseComObject(mxAccessComObject);
|
||||
}
|
||||
}
|
||||
catch (Exception exception) when (failures is not null)
|
||||
{
|
||||
failures.Add(new MxAccessShutdownFailure(
|
||||
"ReleaseComObject",
|
||||
serverHandle: null,
|
||||
itemHandle: null,
|
||||
exception));
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
|
||||
Reference in New Issue
Block a user