Show a target paused by its circuit breaker (closes #385)
check / check (push) Successful in 3m16s
check / check (push) Successful in 3m16s
A target whose circuit breaker had tripped still showed as Active, and its deliveries sat at a bare "retrying" with no attempts. Its row on the webhook page now says deliveries are paused after repeated failures and until when the cooldown ends, adding that one waiting delivery is then sent to test the target; while half-open it says deliveries are held while one tests it, with no time. Waiting deliveries show "next try no earlier than" the later of the cooldown and their own backoff, with the date when not today. The engine gains one read of a breaker's state and remaining cooldown under one lock, and shares the backoff formula. Model: opus-5-5
This commit was merged in pull request #478.
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -181,6 +182,40 @@ func (r *recordingArchives) Renames() []archiveRename {
|
||||
return out
|
||||
}
|
||||
|
||||
// testCircuitBreakers is a delivery.CircuitBreakers that reports, for
|
||||
// each target, the circuit state and cooldown a test gave it with Set,
|
||||
// and a closed breaker for any other target.
|
||||
type testCircuitBreakers struct {
|
||||
mu sync.Mutex
|
||||
states map[string]delivery.CircuitState
|
||||
cooldowns map[string]time.Duration
|
||||
}
|
||||
|
||||
// Set makes the target's breaker read as state, with cooldown left.
|
||||
func (b *testCircuitBreakers) Set(
|
||||
targetID string, state delivery.CircuitState, cooldown time.Duration,
|
||||
) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if b.states == nil {
|
||||
b.states = map[string]delivery.CircuitState{}
|
||||
b.cooldowns = map[string]time.Duration{}
|
||||
}
|
||||
|
||||
b.states[targetID] = state
|
||||
b.cooldowns[targetID] = cooldown
|
||||
}
|
||||
|
||||
func (b *testCircuitBreakers) StateAndCooldown(
|
||||
targetID string,
|
||||
) (delivery.CircuitState, time.Duration) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
return b.states[targetID], b.cooldowns[targetID]
|
||||
}
|
||||
|
||||
// newTestApp returns an app whose RequireStart fails the test when
|
||||
// starting takes longer than fx's default start timeout of 15s. That
|
||||
// limit catches a start that hangs, not a busy host: measured with make
|
||||
@@ -231,6 +266,12 @@ func newTestAppWithConfig(
|
||||
func(r *recordingArchives) delivery.Archives {
|
||||
return r
|
||||
},
|
||||
func() *testCircuitBreakers {
|
||||
return &testCircuitBreakers{}
|
||||
},
|
||||
func(b *testCircuitBreakers) delivery.CircuitBreakers {
|
||||
return b
|
||||
},
|
||||
metrics.NewRegistry,
|
||||
metrics.New,
|
||||
middleware.New,
|
||||
|
||||
Reference in New Issue
Block a user