mirror of
https://github.com/status-im/consul.git
synced 2025-01-10 13:55:55 +00:00
0ac8ae6c3b
* Fix xDS deadlock due to syncLoop termination. This fixes an issue where agentless xDS streams can deadlock permanently until a server is restarted. When this issue occurs, no new proxies are able to successfully connect to the server. Effectively, the trigger for this deadlock stems from the following return statement: https://github.com/hashicorp/consul/blob/v1.18.0/agent/proxycfg-sources/catalog/config_source.go#L199-L202 When this happens, the entire `syncLoop()` terminates and stops consuming from the following channel: https://github.com/hashicorp/consul/blob/v1.18.0/agent/proxycfg-sources/catalog/config_source.go#L182-L192 Which results in the `ConfigSource.cleanup()` function never receiving a response and holding a mutex indefinitely: https://github.com/hashicorp/consul/blob/v1.18.0/agent/proxycfg-sources/catalog/config_source.go#L241-L247 Because this mutex is shared, it effectively deadlocks the server's ability to process new xDS streams. ---- The fix to this issue involves removing the `chan chan struct{}` used like an RPC-over-channels pattern and replacing it with two distinct channels: + `stopSyncLoopCh` - indicates that the `syncLoop()` should terminate soon. + `syncLoopDoneCh` - indicates that the `syncLoop()` has terminated. Splitting these two concepts out and deferring a `close(syncLoopDoneCh)` in the `syncLoop()` function ensures that the deadlock above should no longer occur. We also now evict xDS connections of all proxies for the corresponding `syncLoop()` whenever it encounters an irrecoverable error. This is done by hoisting the new `syncLoopDoneCh` upwards so that it's visible to the xDS delta processing. Prior to this fix, the behavior was to simply orphan them so they would never receive catalog-registration or service-defaults updates. * Add changelog.
61 lines
1.4 KiB
Go
61 lines
1.4 KiB
Go
// Code generated by mockery v2.37.1. DO NOT EDIT.
|
|
|
|
package catalog
|
|
|
|
import (
|
|
context "context"
|
|
|
|
limiter "github.com/hashicorp/consul/agent/grpc-external/limiter"
|
|
mock "github.com/stretchr/testify/mock"
|
|
)
|
|
|
|
// MockSessionLimiter is an autogenerated mock type for the SessionLimiter type
|
|
type MockSessionLimiter struct {
|
|
mock.Mock
|
|
}
|
|
|
|
// BeginSession provides a mock function with given fields:
|
|
func (_m *MockSessionLimiter) BeginSession() (limiter.Session, error) {
|
|
ret := _m.Called()
|
|
|
|
var r0 limiter.Session
|
|
var r1 error
|
|
if rf, ok := ret.Get(0).(func() (limiter.Session, error)); ok {
|
|
return rf()
|
|
}
|
|
if rf, ok := ret.Get(0).(func() limiter.Session); ok {
|
|
r0 = rf()
|
|
} else {
|
|
if ret.Get(0) != nil {
|
|
r0 = ret.Get(0).(limiter.Session)
|
|
}
|
|
}
|
|
|
|
if rf, ok := ret.Get(1).(func() error); ok {
|
|
r1 = rf()
|
|
} else {
|
|
r1 = ret.Error(1)
|
|
}
|
|
|
|
return r0, r1
|
|
}
|
|
|
|
// Run provides a mock function with given fields: ctx
|
|
func (_m *MockSessionLimiter) Run(ctx context.Context) {
|
|
_m.Called(ctx)
|
|
}
|
|
|
|
// NewMockSessionLimiter creates a new instance of MockSessionLimiter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
|
// The first argument is typically a *testing.T value.
|
|
func NewMockSessionLimiter(t interface {
|
|
mock.TestingT
|
|
Cleanup(func())
|
|
}) *MockSessionLimiter {
|
|
mock := &MockSessionLimiter{}
|
|
mock.Mock.Test(t)
|
|
|
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
|
|
|
return mock
|
|
}
|