Merge pull request 'pair-adapter-debug' (#121) from pair-adapter-debug into 2.0.2

Reviewed-on: #121
This commit was merged in pull request #121.
This commit is contained in:
2025-12-30 14:29:53 +00:00

View File

@@ -1423,7 +1423,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
private Task _visibilityGraceTask; private Task _visibilityGraceTask;
private async Task DownloadAndApplyCharacterAsync(Guid applicationBase, CharacterData charaData, Dictionary<ObjectKind, HashSet<PlayerChanges>> updatedData, private async Task DownloadAndApplyCharacterAsync(Guid applicationBase, CharacterData charaData, Dictionary<ObjectKind, HashSet<PlayerChanges>> updatedData,
bool updateModdedPaths, bool updateManip, Dictionary<(string GamePath, string? Hash), string>? cachedModdedPaths, CancellationToken downloadToken) bool updateModdedPaths, bool updateManip, Dictionary<(string GamePath, string? Hash), string>? cachedModdedPaths, CancellationToken downloadToken)
{ {
var concurrencyLease = await _pairProcessingLimiter.AcquireAsync(downloadToken).ConfigureAwait(false); var concurrencyLease = await _pairProcessingLimiter.AcquireAsync(downloadToken).ConfigureAwait(false);
try try
@@ -1577,24 +1577,37 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
RecordFailure("Handler not available for application", "HandlerUnavailable"); RecordFailure("Handler not available for application", "HandlerUnavailable");
return; return;
} }
_applicationCancellationTokenSource = _applicationCancellationTokenSource.CancelRecreate() ?? new CancellationTokenSource();
var appToken = _applicationCancellationTokenSource?.Token; if (_applicationTask != null && !_applicationTask.IsCompleted)
while ((!_applicationTask?.IsCompleted ?? false)
&& !downloadToken.IsCancellationRequested
&& (!appToken?.IsCancellationRequested ?? false))
{ {
Logger.LogDebug("[BASE-{appBase}] Waiting for current data application (Id: {id}) for player ({handler}) to finish", applicationBase, _applicationId, PlayerName); Logger.LogDebug("[BASE-{appBase}] Cancelling current data application (Id: {id}) for player ({handler})", applicationBase, _applicationId, PlayerName);
await Task.Delay(250).ConfigureAwait(false);
var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(downloadToken, timeoutCts.Token);
try
{
await _applicationTask.WaitAsync(combinedCts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
Logger.LogWarning("[BASE-{appBase}] Timeout waiting for application task {id} to complete, proceeding anyway", applicationBase, _applicationId);
}
finally
{
timeoutCts.Dispose();
combinedCts.Dispose();
}
} }
if (downloadToken.IsCancellationRequested || (appToken?.IsCancellationRequested ?? false)) if (downloadToken.IsCancellationRequested)
{ {
_forceFullReapply = true; _forceFullReapply = true;
RecordFailure("Application cancelled", "Cancellation"); RecordFailure("Application cancelled", "Cancellation");
return; return;
} }
_applicationCancellationTokenSource = _applicationCancellationTokenSource.CancelRecreate() ?? new CancellationTokenSource();
var token = _applicationCancellationTokenSource.Token; var token = _applicationCancellationTokenSource.Token;
_applicationTask = ApplyCharacterDataAsync(applicationBase, handlerForApply, charaData, updatedData, updateModdedPaths, updateManip, moddedPaths, wantsModApply, pendingModReapply, token); _applicationTask = ApplyCharacterDataAsync(applicationBase, handlerForApply, charaData, updatedData, updateModdedPaths, updateManip, moddedPaths, wantsModApply, pendingModReapply, token);