frostfs-sdk-go/pool/tree/circuitbreaker_test.go
Alex Vanin 06ef257ddc
Some checks failed
DCO / DCO (pull_request) Successful in 29s
Code generation / Generate proto (pull_request) Successful in 30s
Tests and linters / Lint (pull_request) Failing after 39s
Tests and linters / Tests (pull_request) Successful in 44s
[#339] pool/tree: Do not lock mutex on circuit break function
Circuit break function may take some time to execute so it should
not be executed when lock is enabled.

Signed-off-by: Alex Vanin <a.vanin@yadro.com>
2025-03-04 14:41:01 +03:00

68 lines
1.9 KiB
Go

package tree
import (
"errors"
"runtime"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestCircuitBreaker(t *testing.T) {
remoteErr := errors.New("service is being synchronized")
breakDuration := 1 * time.Second
threshold := 10
cb := newCircuitBreaker(breakDuration, threshold)
// Hit threshold
for i := 0; i < threshold; i++ {
err := cb.Do(1, func() error { return remoteErr })
require.ErrorIs(t, err, remoteErr)
}
// Different client should not be affected by threshold
require.NoError(t, cb.Do(2, func() error { return nil }))
// Immediate request should return circuit breaker error
require.ErrorIs(t, cb.Do(1, func() error { return nil }), ErrCBClosed)
// Request after breakDuration should be ok
time.Sleep(breakDuration)
require.NoError(t, cb.Do(1, func() error { return nil }))
// Try hitting threshold one more time after break duration
for i := 0; i < threshold; i++ {
err := cb.Do(1, func() error { return remoteErr })
require.ErrorIs(t, err, remoteErr)
}
// Immediate request should return circuit breaker error
require.ErrorIs(t, cb.Do(1, func() error { return nil }), ErrCBClosed)
}
func TestCircuitBreakerNoBlock(t *testing.T) {
remoteErr := errors.New("service is being synchronized")
funcDuration := 2 * time.Second
threshold := 100
cb := newCircuitBreaker(1*time.Minute, threshold)
slowFunc := func() error {
time.Sleep(funcDuration)
return remoteErr
}
for i := 0; i < threshold; i++ {
// run in multiple goroutines Do function and make sure it is not
go func() {
cb.Do(1, slowFunc)
}()
}
// wait for one slow func duration + some delta
time.Sleep(funcDuration + 100*time.Millisecond)
runtime.Gosched()
// expect that all goroutines were not blocked by mutex in circuit breaker
// therefore all functions are done and circuit is closed
require.ErrorIs(t, cb.Do(1, func() error { return nil }), ErrCBClosed)
}