refactor: merge retry target type into http (max_retries=0 = fire-and-forget)
All checks were successful
check / check (push) Successful in 1m46s

This commit is contained in:
clawbot
2026-03-01 23:51:55 -08:00
parent 4dd4dfa5eb
commit 25e27cc57f
7 changed files with 150 additions and 105 deletions

View File

@@ -133,7 +133,8 @@ type Engine struct {
workers int
// circuitBreakers stores a *CircuitBreaker per target ID. Only used
// for retry targets — HTTP, database, and log targets do not need
// for HTTP targets with MaxRetries > 0 — fire-and-forget HTTP targets
// (MaxRetries == 0), database targets, and log targets do not need
// circuit breakers because they either fire once or are local ops.
circuitBreakers sync.Map
}
@@ -829,9 +830,7 @@ func (e *Engine) sweepWebhookRetries(ctx context.Context, webhookID string) {
func (e *Engine) processDelivery(ctx context.Context, webhookDB *gorm.DB, d *database.Delivery, task *DeliveryTask) {
switch d.Target.Type {
case database.TargetTypeHTTP:
e.deliverHTTP(ctx, webhookDB, d)
case database.TargetTypeRetry:
e.deliverRetry(ctx, webhookDB, d, task)
e.deliverHTTP(ctx, webhookDB, d, task)
case database.TargetTypeDatabase:
e.deliverDatabase(webhookDB, d)
case database.TargetTypeLog:
@@ -845,47 +844,43 @@ func (e *Engine) processDelivery(ctx context.Context, webhookDB *gorm.DB, d *dat
}
}
func (e *Engine) deliverHTTP(_ context.Context, webhookDB *gorm.DB, d *database.Delivery) {
func (e *Engine) deliverHTTP(_ context.Context, webhookDB *gorm.DB, d *database.Delivery, task *DeliveryTask) {
cfg, err := e.parseHTTPConfig(d.Target.Config)
if err != nil {
e.log.Error("invalid HTTP target config",
"target_id", d.TargetID,
"error", err,
)
e.recordResult(webhookDB, d, 1, false, 0, "", err.Error(), 0)
e.updateDeliveryStatus(webhookDB, d, database.DeliveryStatusFailed)
return
}
statusCode, respBody, duration, err := e.doHTTPRequest(cfg, &d.Event)
success := err == nil && statusCode >= 200 && statusCode < 300
errMsg := ""
if err != nil {
errMsg = err.Error()
}
e.recordResult(webhookDB, d, 1, success, statusCode, respBody, errMsg, duration)
if success {
e.updateDeliveryStatus(webhookDB, d, database.DeliveryStatusDelivered)
} else {
e.updateDeliveryStatus(webhookDB, d, database.DeliveryStatusFailed)
}
}
func (e *Engine) deliverRetry(_ context.Context, webhookDB *gorm.DB, d *database.Delivery, task *DeliveryTask) {
cfg, err := e.parseHTTPConfig(d.Target.Config)
if err != nil {
e.log.Error("invalid retry target config",
"target_id", d.TargetID,
"error", err,
)
e.recordResult(webhookDB, d, task.AttemptNum, false, 0, "", err.Error(), 0)
e.updateDeliveryStatus(webhookDB, d, database.DeliveryStatusFailed)
return
}
maxRetries := d.Target.MaxRetries
// Fire-and-forget mode: max_retries == 0 means attempt once with no
// circuit breaker and no retry scheduling.
if maxRetries == 0 {
statusCode, respBody, duration, reqErr := e.doHTTPRequest(cfg, &d.Event)
success := reqErr == nil && statusCode >= 200 && statusCode < 300
errMsg := ""
if reqErr != nil {
errMsg = reqErr.Error()
}
e.recordResult(webhookDB, d, 1, success, statusCode, respBody, errMsg, duration)
if success {
e.updateDeliveryStatus(webhookDB, d, database.DeliveryStatusDelivered)
} else {
e.updateDeliveryStatus(webhookDB, d, database.DeliveryStatusFailed)
}
return
}
// Retry mode: max_retries > 0 — use circuit breaker and exponential backoff.
// Check the circuit breaker for this target before attempting delivery.
cb := e.getCircuitBreaker(task.TargetID)
if !cb.Allow() {
@@ -910,12 +905,12 @@ func (e *Engine) deliverRetry(_ context.Context, webhookDB *gorm.DB, d *database
// Attempt delivery immediately — backoff is handled by the timer
// that triggered this call, not by polling.
statusCode, respBody, duration, err := e.doHTTPRequest(cfg, &d.Event)
statusCode, respBody, duration, reqErr := e.doHTTPRequest(cfg, &d.Event)
success := err == nil && statusCode >= 200 && statusCode < 300
success := reqErr == nil && statusCode >= 200 && statusCode < 300
errMsg := ""
if err != nil {
errMsg = err.Error()
if reqErr != nil {
errMsg = reqErr.Error()
}
e.recordResult(webhookDB, d, attemptNum, success, statusCode, respBody, errMsg, duration)
@@ -929,11 +924,6 @@ func (e *Engine) deliverRetry(_ context.Context, webhookDB *gorm.DB, d *database
// Delivery failed — record failure in circuit breaker
cb.RecordFailure()
maxRetries := d.Target.MaxRetries
if maxRetries <= 0 {
maxRetries = 5 // default
}
if attemptNum >= maxRetries {
e.updateDeliveryStatus(webhookDB, d, database.DeliveryStatusFailed)
} else {