refactor: merge TaskRunner failure handlers and reuse NullIfBlank

Unify the near-identical HandleFailure/MarkFailed into a single MarkFailed that
always persists the failed state and never throws, and replace the inline
null-if-blank checks in ListMcpTools with the existing extension.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-05-30 15:51:14 +02:00
parent ce9fadc0b5
commit 1856943925
2 changed files with 14 additions and 23 deletions

View File

@@ -129,12 +129,12 @@ public sealed class TaskRunner
}
else
{
await HandleFailure(task.Id, task.Title, slot, retryResult);
await MarkFailed(task.Id, task.Title, slot, retryResult.ErrorMarkdown, retryResult.TurnCount);
}
}
else
{
await HandleFailure(task.Id, task.Title, slot, result);
await MarkFailed(task.Id, task.Title, slot, result.ErrorMarkdown, result.TurnCount);
}
}
@@ -210,7 +210,7 @@ public sealed class TaskRunner
}
else
{
await HandleFailure(taskId, task.Title, slot, result);
await MarkFailed(taskId, task.Title, slot, result.ErrorMarkdown, result.TurnCount);
}
await _broadcaster.TaskUpdated(taskId);
@@ -331,26 +331,17 @@ public sealed class TaskRunner
task.Id, result.TurnCount, result.TokensIn, result.TokensOut);
}
private async Task HandleFailure(string taskId, string taskTitle, string slot, RunResult result)
{
// Intentionally does not accept a CancellationToken: this is the
// terminal write for a failed task and must always be persisted.
var finishedAt = DateTime.UtcNow;
await _state.FailAsync(taskId, finishedAt, result.ErrorMarkdown, CancellationToken.None);
await _broadcaster.WorkerLog($"Finished \"{taskTitle}\" (failed)", WorkerLogLevel.Error, DateTime.UtcNow);
await _broadcaster.TaskFinished(slot, taskId, "failed", finishedAt);
_logger.LogWarning("Task {TaskId} failed (turns={Turns}): {Error}", taskId, result.TurnCount, result.ErrorMarkdown);
}
private async Task MarkFailed(string taskId, string taskTitle, string slot, string error)
private async Task MarkFailed(string taskId, string taskTitle, string slot, string? error, int turnCount = 0)
{
// Terminal write for a failed task: never cancel (the status must always
// be persisted) and never throw (a logging failure must not mask the error).
try
{
var now = DateTime.UtcNow;
// Terminal write — never cancel.
await _state.FailAsync(taskId, now, error, CancellationToken.None);
var finishedAt = DateTime.UtcNow;
await _state.FailAsync(taskId, finishedAt, error, CancellationToken.None);
await _broadcaster.WorkerLog($"Finished \"{taskTitle}\" (failed)", WorkerLogLevel.Error, DateTime.UtcNow);
await _broadcaster.TaskFinished(slot, taskId, "failed", now);
await _broadcaster.TaskFinished(slot, taskId, "failed", finishedAt);
_logger.LogWarning("Task {TaskId} failed (turns={Turns}): {Error}", taskId, turnCount, error);
}
catch (Exception ex)
{