Keep batch notification failures out of report counts
This commit is contained in:
@@ -154,13 +154,14 @@ func (e BatchError) Error() string {
|
||||
if e.Result == nil {
|
||||
return "batch failed"
|
||||
}
|
||||
if batchNotificationFailed(e.Result) && batchReportFailures(e.Result) == 0 {
|
||||
failedReports := batchReportFailures(e.Result)
|
||||
if batchNotificationFailed(e.Result) && failedReports == 0 {
|
||||
if e.Result.Notification.Error != "" {
|
||||
return fmt.Sprintf("batch %s notification failed: %s", e.Result.Batch, e.Result.Notification.Error)
|
||||
}
|
||||
return fmt.Sprintf("batch %s notification failed", e.Result.Batch)
|
||||
}
|
||||
return fmt.Sprintf("batch %s failed: %d of %d reports failed", e.Result.Batch, e.Result.Failed, e.Result.Total)
|
||||
return fmt.Sprintf("batch %s failed: %d of %d reports failed", e.Result.Batch, failedReports, len(e.Result.Reports))
|
||||
}
|
||||
|
||||
func batchNotificationFailed(result *BatchResult) bool {
|
||||
@@ -291,7 +292,7 @@ func RunBatch(ctx context.Context, req BatchRequest) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.Failed > 0 {
|
||||
if result.Failed > 0 || batchNotificationFailed(result) {
|
||||
return BatchError{Result: result}
|
||||
}
|
||||
return nil
|
||||
@@ -370,13 +371,10 @@ func RunBatchDetailed(ctx context.Context, req BatchRequest) (*BatchResult, erro
|
||||
result.Reports = append(result.Reports, item)
|
||||
}
|
||||
result.Total = len(result.Reports)
|
||||
batchNotification, err := notifyBatch(ctx, req.Config, req.Batch, batchRunID(startedAt, req.Batch), startedAt, result, plannedReports, req.Notifier)
|
||||
batchNotification, _ := notifyBatch(ctx, req.Config, req.Batch, batchRunID(startedAt, req.Batch), startedAt, result, plannedReports, req.Notifier)
|
||||
if batchNotification != nil {
|
||||
result.Notification = batchNotification
|
||||
}
|
||||
if err != nil {
|
||||
result.Failed++
|
||||
}
|
||||
result.FinishedAt = time.Now()
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
|
||||
@@ -95,6 +97,43 @@ func TestRunBatchDetailedPreflightsAllOutputPaths(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunBatchDetailedRetainsReportCountsWhenNotificationFails(t *testing.T) {
|
||||
bundle := generationBundle(t)
|
||||
bundle.Hourly.Periods = bundle.Hourly.Periods[:1]
|
||||
outputDir := t.TempDir()
|
||||
notifier := &generationNotifier{batchErr: errors.New("distributor unavailable")}
|
||||
result, err := RunBatchDetailed(context.Background(), BatchRequest{
|
||||
Config: generationDistributorConfig(), Batch: BatchMorning,
|
||||
Now: generationTime("2026-05-29T08:30:00-05:00"), WorkingDir: t.TempDir(), OutputDir: outputDir,
|
||||
Collector: &generationCollector{bundle: &bundle}, Executor: &generationExecutor{}, Notifier: notifier,
|
||||
})
|
||||
if err != nil || result == nil || result.Total != len(result.Reports) || result.Succeeded != len(result.Reports) || result.Failed != 0 || result.Notification == nil || result.Notification.Status != "failed" {
|
||||
t.Fatalf("RunBatchDetailed() result/error = %#v/%v", result, err)
|
||||
}
|
||||
for _, item := range result.Reports {
|
||||
if item.Status != "succeeded" || item.OutputPath == "" {
|
||||
t.Fatalf("report result = %#v", item)
|
||||
}
|
||||
if _, statErr := os.Stat(item.OutputPath); statErr != nil {
|
||||
t.Fatalf("published output %q: %v", item.OutputPath, statErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunBatchReturnsNotificationFailureWithoutReportFailureWording(t *testing.T) {
|
||||
bundle := generationBundle(t)
|
||||
bundle.Hourly.Periods = bundle.Hourly.Periods[:1]
|
||||
err := RunBatch(context.Background(), BatchRequest{
|
||||
Config: generationDistributorConfig(), Batch: BatchMorning,
|
||||
Now: generationTime("2026-05-29T08:30:00-05:00"), WorkingDir: t.TempDir(), OutputDir: t.TempDir(),
|
||||
Collector: &generationCollector{bundle: &bundle}, Executor: &generationExecutor{}, Notifier: &generationNotifier{batchErr: errors.New("distributor unavailable")},
|
||||
})
|
||||
var batchErr BatchError
|
||||
if !errors.As(err, &batchErr) || batchErr.Result == nil || batchErr.Result.Failed != 0 || batchErr.Result.Notification == nil || batchErr.Result.Notification.Status != "failed" || !strings.Contains(err.Error(), "notification failed") || strings.Contains(err.Error(), "reports failed") {
|
||||
t.Fatalf("RunBatch() error/result = %v/%#v", err, batchErr.Result)
|
||||
}
|
||||
}
|
||||
|
||||
func generationDistributorConfig() config.Config {
|
||||
cfg := generationConfig()
|
||||
cfg.Notify.Distributor.Enabled = true
|
||||
|
||||
@@ -243,6 +243,7 @@ func generationBundlePointer(t *testing.T) *weatherdata.Bundle {
|
||||
|
||||
type generationNotifier struct {
|
||||
err error
|
||||
batchErr error
|
||||
request NotificationRequest
|
||||
batchRequest batchNotificationRequest
|
||||
batchCalls int
|
||||
@@ -261,7 +262,7 @@ func (n *generationNotifier) NotifyBatch(_ context.Context, request batchNotific
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &NotificationResult{Status: "succeeded", PipelineID: request.PipelineID, BundleID: request.BundleID}, nil
|
||||
return &NotificationResult{Status: "succeeded", PipelineID: request.PipelineID, BundleID: request.BundleID}, n.batchErr
|
||||
}
|
||||
|
||||
func generationBundle(t *testing.T) weatherdata.Bundle {
|
||||
|
||||
Reference in New Issue
Block a user