Fix PowerShell threading issue in multipart upload progress

� CRITICAL POWERSHELL THREADING FIX:

 ROOT CAUSE IDENTIFIED:
  • ProcessQueuedUpdates() was called from background threads (Task.Run)
  • PowerShell cmdlets can only call Write-Progress/Write-Verbose from main thread
  • Error: 'WriteObject and WriteError methods cannot be called from outside...'
  • Background thread progress updates caused cmdlet failures

� SOLUTION IMPLEMENTED:
  • Removed ProcessQueuedUpdates() calls from background threads
  • Added periodic progress processing from main thread
  • Wait with 1-second intervals to process queued updates
  • Maintains real-time progress while respecting PowerShell threading

 TECHNICAL APPROACH:
  • Background threads queue progress updates (thread-safe)
  • Main thread processes updates every 1 second during Task.WaitAll
  • Final processing after all tasks complete
  • Preserves chunk status tracking without threading violations

 PRESERVED FEATURES:
  • Chunk status tracking (Queued, Transferring, Completed, Failed)
  • Enhanced PartInfo with timing and error details
  • Chunk generation logging
  • Real-time progress updates (every 1 second)

� RESULT:
  • Multipart uploads work reliably again
  • Progress updates every second from main thread
  • No PowerShell threading violations
  • Maintains all enhanced features safely

Critical fix for PowerShell cmdlet threading compliance!
This commit is contained in:
PSMinIO Developer
2025-07-14 22:19:13 -04:00
parent c861ee1cd5
commit c77cca3f9c
2 changed files with 11 additions and 5 deletions
Binary file not shown.
+11 -5
View File
@@ -174,8 +174,7 @@ namespace PSMinIO.Core.S3
SizeFormatter.FormatDuration(partInfo.Duration ?? TimeSpan.Zero));
}
// Process progress updates immediately for real-time display
_progressCollector.ProcessQueuedUpdates();
// Don't call ProcessQueuedUpdates from background thread - PowerShell threading issue
}
catch (Exception ex)
{
@@ -189,7 +188,6 @@ namespace PSMinIO.Core.S3
_progressCollector.QueueVerboseMessage("Failed to upload part {0}/{1}: {2}",
partNum, totalParts, ex.Message);
_progressCollector.ProcessQueuedUpdates();
throw new InvalidOperationException($"Failed to upload part {partNum}: {ex.Message}", ex);
}
@@ -202,8 +200,16 @@ namespace PSMinIO.Core.S3
uploadTasks.Add(uploadTask);
}
// Wait for all uploads to complete
Task.WaitAll(uploadTasks.ToArray());
// Wait for all uploads to complete with periodic progress updates
var allTasks = uploadTasks.ToArray();
while (!Task.WaitAll(allTasks, 1000)) // Wait 1 second at a time
{
// Process progress updates from main thread every second
_progressCollector.ProcessQueuedUpdates();
}
// Process final updates
_progressCollector.ProcessQueuedUpdates();
// Complete multipart upload
var sortedParts = parts.Values.OrderBy(p => p.PartNumber).ToList();