potential resolve disposal crashes and race conditions

This commit is contained in:
choco
2025-12-21 22:34:39 +01:00
parent 34bbc34b5b
commit 0ec423e65c

View File

@@ -1,4 +1,4 @@
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using LightlessSync.API.Dto.User; using LightlessSync.API.Dto.User;
using LightlessSync.Services.ActorTracking; using LightlessSync.Services.ActorTracking;
using LightlessSync.Services.Mediator; using LightlessSync.Services.Mediator;
@@ -33,6 +33,7 @@ public class LightFinderScannerService : DisposableMediatorSubscriberBase
private const int _maxQueueSize = 100; private const int _maxQueueSize = 100;
private volatile bool _batchRunning = false; private volatile bool _batchRunning = false;
private volatile bool _disposed = false;
public IReadOnlyDictionary<string, BroadcastEntry> BroadcastCache => _broadcastCache; public IReadOnlyDictionary<string, BroadcastEntry> BroadcastCache => _broadcastCache;
public readonly record struct BroadcastEntry(bool IsBroadcasting, DateTime ExpiryTime, string? GID); public readonly record struct BroadcastEntry(bool IsBroadcasting, DateTime ExpiryTime, string? GID);
@@ -63,6 +64,9 @@ public class LightFinderScannerService : DisposableMediatorSubscriberBase
public void Update() public void Update()
{ {
if (_disposed)
return;
_frameCounter++; _frameCounter++;
var lookupsThisFrame = 0; var lookupsThisFrame = 0;
@@ -104,7 +108,14 @@ public class LightFinderScannerService : DisposableMediatorSubscriberBase
private async Task BatchUpdateBroadcastCacheAsync(List<string> cids) private async Task BatchUpdateBroadcastCacheAsync(List<string> cids)
{ {
if (_disposed)
return;
var results = await _broadcastService.AreUsersBroadcastingAsync(cids).ConfigureAwait(false); var results = await _broadcastService.AreUsersBroadcastingAsync(cids).ConfigureAwait(false);
if (_disposed)
return;
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
foreach (var (cid, info) in results) foreach (var (cid, info) in results)
@@ -123,6 +134,9 @@ public class LightFinderScannerService : DisposableMediatorSubscriberBase
(_, old) => new BroadcastEntry(info.IsBroadcasting, expiry, info.GID)); (_, old) => new BroadcastEntry(info.IsBroadcasting, expiry, info.GID));
} }
if (_disposed)
return;
var activeCids = _broadcastCache var activeCids = _broadcastCache
.Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now) .Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now)
.Select(e => e.Key) .Select(e => e.Key)
@@ -134,6 +148,9 @@ public class LightFinderScannerService : DisposableMediatorSubscriberBase
private void OnBroadcastStatusChanged(BroadcastStatusChangedMessage msg) private void OnBroadcastStatusChanged(BroadcastStatusChangedMessage msg)
{ {
if (_disposed)
return;
if (!msg.Enabled) if (!msg.Enabled)
{ {
_broadcastCache.Clear(); _broadcastCache.Clear();
@@ -147,6 +164,9 @@ public class LightFinderScannerService : DisposableMediatorSubscriberBase
private void UpdateSyncshellBroadcasts() private void UpdateSyncshellBroadcasts()
{ {
if (_disposed)
return;
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var newSet = _broadcastCache var newSet = _broadcastCache
.Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now && !string.IsNullOrEmpty(e.Value.GID)) .Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now && !string.IsNullOrEmpty(e.Value.GID))
@@ -230,17 +250,35 @@ public class LightFinderScannerService : DisposableMediatorSubscriberBase
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
_disposed = true;
base.Dispose(disposing); base.Dispose(disposing);
_framework.Update -= OnFrameworkUpdate; _framework.Update -= OnFrameworkUpdate;
if (_cleanupTask != null)
try
{ {
_cleanupTask?.Wait(100, _cleanupCts.Token);
}
_cleanupCts.Cancel(); _cleanupCts.Cancel();
_cleanupCts.Dispose(); }
catch (ObjectDisposedException)
{
// Already disposed, can be ignored :)
}
try
{
_cleanupTask?.Wait(100); _cleanupTask?.Wait(100);
}
catch (Exception)
{
// Task may have already completed or been cancelled?
}
try
{
_cleanupCts.Dispose(); _cleanupCts.Dispose();
} }
catch (ObjectDisposedException)
{
// Already disposed, ignore
}
}
} }