Improve batch runtime diagnostics

This commit is contained in:
Thorsten Sommer 2026-08-11 14:11:39 +02:00
parent b511700c01
commit e9f1373c71
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
3 changed files with 44 additions and 5 deletions

View File

@ -222,6 +222,7 @@ public partial class AssistantBatchProcessing
catch (Exception e) catch (Exception e)
{ {
this.Logger.LogWarning(e, "Was not able to read the results table of the previous batch run at '{ResultsFilePath}'.", resultsFilePath); this.Logger.LogWarning(e, "Was not able to read the results table of the previous batch run at '{ResultsFilePath}'.", resultsFilePath);
await this.MessageBus.SendWarning(new(Icons.Material.Filled.Warning, T("Was not able to read the results table of the previous run. Its completed documents cannot be restored and will be processed again.")));
} }
return results; return results;

View File

@ -1,3 +1,4 @@
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
@ -79,6 +80,14 @@ public partial class AssistantBatchProcessing
private async Task RunBatchAsync(string resolvedOutputDirectory) private async Task RunBatchAsync(string resolvedOutputDirectory)
{ {
this.isProcessingBatch = true; this.isProcessingBatch = true;
var stopwatch = Stopwatch.StartNew();
this.Logger.LogInformation(
"Batch processing started. InputDirectory='{InputDirectory}', OutputDirectory='{OutputDirectory}', TotalFiles={TotalFiles}, RestoredFiles={RestoredFiles}, Model='{Model}'.",
this.inputDirectory,
resolvedOutputDirectory,
this.fileResults.Count,
this.fileResults.Count(fileResult => fileResult.Status is BatchProcessingFileStatus.DONE),
this.ProviderSettings.Model);
// We use the cancellation token of the assistant base class, which // We use the cancellation token of the assistant base class, which
// creates it before it calls us and disposes it after we returned. // creates it before it calls us and disposes it after we returned.
@ -119,11 +128,33 @@ public partial class AssistantBatchProcessing
} }
finally finally
{ {
stopwatch.Stop();
var doneFiles = this.fileResults.Count(fileResult => fileResult.Status is BatchProcessingFileStatus.DONE);
var failedFiles = this.fileResults.Count(fileResult => fileResult.Status is BatchProcessingFileStatus.FAILED);
var canceledFiles = this.fileResults.Count(fileResult => fileResult.Status is BatchProcessingFileStatus.CANCELED);
this.Logger.LogInformation(
"Batch processing finished after {ElapsedMilliseconds} ms. TotalFiles={TotalFiles}, DoneFiles={DoneFiles}, FailedFiles={FailedFiles}, CanceledFiles={CanceledFiles}, OutputWriteFailed={OutputWriteFailed}.",
stopwatch.ElapsedMilliseconds,
this.fileResults.Count,
doneFiles,
failedFiles,
canceledFiles,
this.hasReportedWriteFailure);
// The cancellation token source belongs to the base class, which // The cancellation token source belongs to the base class, which
// disposes it and evaluates its state after we returned: // disposes it and evaluates its state after we returned:
this.isProcessingBatch = false; this.isProcessingBatch = false;
await this.CheckpointAssistantSession(); await this.CheckpointAssistantSession();
await this.RefreshAssistantUIAsync(); await this.RefreshAssistantUIAsync();
if (failedFiles > 0)
{
var failureMessage = failedFiles == 1
? T("The batch run finished, but one file could not be processed. See the progress table and log for details.")
: string.Format(T("The batch run finished, but {0} files could not be processed. See the progress table and log for details."), failedFiles);
await this.MessageBus.SendError(new(Icons.Material.Filled.Error, failureMessage));
}
} }
} }
@ -143,7 +174,7 @@ public partial class AssistantBatchProcessing
} }
catch (Exception e) catch (Exception e)
{ {
this.FinishFileResult(fileResult, BatchProcessingFileStatus.FAILED, string.Format(T("Was not able to read the file: {0}"), e.Message)); this.FinishFileResult(fileResult, BatchProcessingFileStatus.FAILED, string.Format(T("Was not able to read the file: {0}"), e.Message), e);
return; return;
} }
@ -185,7 +216,7 @@ public partial class AssistantBatchProcessing
} }
catch (Exception e) catch (Exception e)
{ {
this.FinishFileResult(fileResult, BatchProcessingFileStatus.FAILED, string.Format(T("The AI request failed: {0}"), e.Message)); this.FinishFileResult(fileResult, BatchProcessingFileStatus.FAILED, string.Format(T("The AI request failed: {0}"), e.Message), e);
return; return;
} }
@ -215,21 +246,26 @@ public partial class AssistantBatchProcessing
} }
catch (Exception e) catch (Exception e)
{ {
this.FinishFileResult(fileResult, BatchProcessingFileStatus.FAILED, string.Format(T("Was not able to write the result file: {0}"), e.Message)); this.FinishFileResult(fileResult, BatchProcessingFileStatus.FAILED, string.Format(T("Was not able to write the result file: {0}"), e.Message), e);
} }
} }
else else
this.FinishFileResult(fileResult, BatchProcessingFileStatus.DONE, string.Empty); this.FinishFileResult(fileResult, BatchProcessingFileStatus.DONE, string.Empty);
} }
private void FinishFileResult(BatchProcessingFileResult fileResult, BatchProcessingFileStatus status, string message) private void FinishFileResult(BatchProcessingFileResult fileResult, BatchProcessingFileStatus status, string message, Exception? exception = null)
{ {
fileResult.Status = status; fileResult.Status = status;
fileResult.Message = message; fileResult.Message = message;
fileResult.ProcessedAt = DateTimeOffset.Now; fileResult.ProcessedAt = DateTimeOffset.Now;
if (status is BatchProcessingFileStatus.FAILED) if (status is not BatchProcessingFileStatus.FAILED)
return;
if (exception is null)
this.Logger.LogWarning("Batch processing of file '{FilePath}' failed: {Message}", fileResult.FilePath, message); this.Logger.LogWarning("Batch processing of file '{FilePath}' failed: {Message}", fileResult.FilePath, message);
else
this.Logger.LogError(exception, "Batch processing of file '{FilePath}' failed: {Message}", fileResult.FilePath, message);
} }
private async Task CancelBatchProcessingAsync() private async Task CancelBatchProcessingAsync()

View File

@ -204,6 +204,7 @@ public partial class AssistantBatchProcessing
} }
catch (Exception e) catch (Exception e)
{ {
this.Logger.LogError(e, "Was not able to enumerate batch input files in '{InputDirectory}'.", this.inputDirectory);
this.AddInputIssue(string.Format(T("Was not able to read the input folder: {0}"), e.Message)); this.AddInputIssue(string.Format(T("Was not able to read the input folder: {0}"), e.Message));
return null; return null;
} }
@ -220,6 +221,7 @@ public partial class AssistantBatchProcessing
} }
catch (Exception e) catch (Exception e)
{ {
this.Logger.LogError(e, "Was not able to create the batch output folder '{OutputDirectory}'.", resolvedOutputDirectory);
this.AddInputIssue(string.Format(T("Was not able to create the output folder: {0}"), e.Message)); this.AddInputIssue(string.Format(T("Was not able to create the output folder: {0}"), e.Message));
return null; return null;
} }