Preserve batch cancellation outcomes
This commit is contained in:
@@ -3,6 +3,7 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -100,6 +101,7 @@ type BatchResult struct {
|
||||
Total int `json:"total"`
|
||||
Succeeded int `json:"succeeded"`
|
||||
Failed int `json:"failed"`
|
||||
Canceled int `json:"canceled,omitempty"`
|
||||
Notification *BatchNotificationResult `json:"notification,omitempty"`
|
||||
Reports []BatchReportResult `json:"reports"`
|
||||
}
|
||||
@@ -143,12 +145,19 @@ type BatchReportResult struct {
|
||||
|
||||
type BatchError struct {
|
||||
Result *BatchResult
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e BatchError) Error() string {
|
||||
if e.Result == nil {
|
||||
return "batch failed"
|
||||
}
|
||||
if errors.Is(e.Cause, context.DeadlineExceeded) {
|
||||
return fmt.Sprintf("batch %s deadline exceeded", e.Result.Batch)
|
||||
}
|
||||
if errors.Is(e.Cause, context.Canceled) || e.Result.Canceled > 0 {
|
||||
return fmt.Sprintf("batch %s canceled", e.Result.Batch)
|
||||
}
|
||||
failedReports := batchReportFailures(e.Result)
|
||||
if batchNotificationFailed(e.Result) && failedReports == 0 {
|
||||
if e.Result.Notification.Error != "" {
|
||||
@@ -159,6 +168,10 @@ func (e BatchError) Error() string {
|
||||
return fmt.Sprintf("batch %s failed: %d of %d reports failed", e.Result.Batch, failedReports, len(e.Result.Reports))
|
||||
}
|
||||
|
||||
func (e BatchError) Unwrap() error {
|
||||
return e.Cause
|
||||
}
|
||||
|
||||
func batchNotificationFailed(result *BatchResult) bool {
|
||||
return result != nil && result.Notification != nil && result.Notification.Status == "failed"
|
||||
}
|
||||
@@ -344,7 +357,12 @@ func RunBatchDetailed(ctx context.Context, req BatchRequest) (*BatchResult, erro
|
||||
if req.Batch == BatchEvening || req.Batch == BatchMorning {
|
||||
startedAt := now
|
||||
result := &BatchResult{Batch: req.Batch, StartedAt: startedAt}
|
||||
for _, planned := range plannedReports {
|
||||
var cancellation error
|
||||
for index, planned := range plannedReports {
|
||||
if cancellation = batchCancellationCause(ctx, nil); cancellation != nil {
|
||||
appendCanceledBatchReports(result, plannedReports[index:])
|
||||
break
|
||||
}
|
||||
resolved := planned.Resolved
|
||||
item := batchReportResult(planned)
|
||||
reportResult, err := generatePromptReport(ctx, promptReportRequest{
|
||||
@@ -364,14 +382,26 @@ func RunBatchDetailed(ctx context.Context, req BatchRequest) (*BatchResult, erro
|
||||
copyBatchReportDetails(&item, reportResult)
|
||||
}
|
||||
if err != nil {
|
||||
item.Status = "failed"
|
||||
item.Error = err.Error()
|
||||
result.Failed++
|
||||
if cancellation = batchCancellationCause(ctx, err); cancellation != nil {
|
||||
item.Status = "canceled"
|
||||
result.Canceled++
|
||||
} else {
|
||||
item.Status = "failed"
|
||||
item.Error = err.Error()
|
||||
result.Failed++
|
||||
}
|
||||
} else {
|
||||
item.Status = "succeeded"
|
||||
result.Succeeded++
|
||||
}
|
||||
result.Reports = append(result.Reports, item)
|
||||
if cancellation == nil {
|
||||
cancellation = batchCancellationCause(ctx, nil)
|
||||
}
|
||||
if cancellation != nil {
|
||||
appendCanceledBatchReports(result, plannedReports[index+1:])
|
||||
break
|
||||
}
|
||||
}
|
||||
result.Total = len(result.Reports)
|
||||
batchNotification := notifyBatch(ctx, req.Config, req.Batch, batchRunID(startedAt, req.Batch), startedAt, result, plannedReports, req.Notifier)
|
||||
@@ -379,11 +409,38 @@ func RunBatchDetailed(ctx context.Context, req BatchRequest) (*BatchResult, erro
|
||||
result.Notification = batchNotification
|
||||
}
|
||||
result.FinishedAt = time.Now()
|
||||
return result, nil
|
||||
return result, cancellation
|
||||
}
|
||||
return nil, fmt.Errorf("run is not implemented")
|
||||
}
|
||||
|
||||
func batchCancellationCause(ctx context.Context, err error) error {
|
||||
if ctx != nil {
|
||||
if contextErr := ctx.Err(); contextErr != nil {
|
||||
return contextErr
|
||||
}
|
||||
}
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return context.Canceled
|
||||
}
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return context.DeadlineExceeded
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendCanceledBatchReports(result *BatchResult, plannedReports []plannedBatchReport) {
|
||||
if result == nil {
|
||||
return
|
||||
}
|
||||
for _, planned := range plannedReports {
|
||||
item := batchReportResult(planned)
|
||||
item.Status = "canceled"
|
||||
result.Reports = append(result.Reports, item)
|
||||
result.Canceled++
|
||||
}
|
||||
}
|
||||
|
||||
func copyBatchReportDetails(item *BatchReportResult, result *ReportResult) {
|
||||
item.LLMDebugPath = result.LLMDebugPath
|
||||
item.OutputPath = result.OutputPath
|
||||
|
||||
Reference in New Issue
Block a user