mirror of
https://github.com/zitadel/zitadel.git
synced 2025-10-25 06:08:56 +00:00
feat: handle instanceID in projections (#3442)
* feat: handle instanceID in projections * rename functions * fix key lock * fix import
This commit is contained in:
@@ -5,44 +5,45 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockLocker is a mock of Locker interface
|
||||
// MockLocker is a mock of Locker interface.
|
||||
type MockLocker struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockLockerMockRecorder
|
||||
}
|
||||
|
||||
// MockLockerMockRecorder is the mock recorder for MockLocker
|
||||
// MockLockerMockRecorder is the mock recorder for MockLocker.
|
||||
type MockLockerMockRecorder struct {
|
||||
mock *MockLocker
|
||||
}
|
||||
|
||||
// NewMockLocker creates a new mock instance
|
||||
// NewMockLocker creates a new mock instance.
|
||||
func NewMockLocker(ctrl *gomock.Controller) *MockLocker {
|
||||
mock := &MockLocker{ctrl: ctrl}
|
||||
mock.recorder = &MockLockerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockLocker) EXPECT() *MockLockerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Renew mocks base method
|
||||
func (m *MockLocker) Renew(lockerID, viewModel string, waitTime time.Duration) error {
|
||||
// Renew mocks base method.
|
||||
func (m *MockLocker) Renew(lockerID, viewModel, instanceID string, waitTime time.Duration) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Renew", lockerID, viewModel, waitTime)
|
||||
ret := m.ctrl.Call(m, "Renew", lockerID, viewModel, instanceID, waitTime)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Renew indicates an expected call of Renew
|
||||
func (mr *MockLockerMockRecorder) Renew(lockerID, viewModel, waitTime interface{}) *gomock.Call {
|
||||
// Renew indicates an expected call of Renew.
|
||||
func (mr *MockLockerMockRecorder) Renew(lockerID, viewModel, instanceID, waitTime interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Renew", reflect.TypeOf((*MockLocker)(nil).Renew), lockerID, viewModel, waitTime)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Renew", reflect.TypeOf((*MockLocker)(nil).Renew), lockerID, viewModel, instanceID, waitTime)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
const systemID = "system"
|
||||
|
||||
type Spooler struct {
|
||||
handlers []query.Handler
|
||||
locker Locker
|
||||
@@ -26,7 +28,7 @@ type Spooler struct {
|
||||
}
|
||||
|
||||
type Locker interface {
|
||||
Renew(lockerID, viewModel string, waitTime time.Duration) error
|
||||
Renew(lockerID, viewModel, instanceID string, waitTime time.Duration) error
|
||||
}
|
||||
|
||||
type spooledHandler struct {
|
||||
@@ -138,19 +140,6 @@ func (s *spooledHandler) query(ctx context.Context) ([]*models.Event, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
factory := models.FactoryFromSearchQuery(query)
|
||||
sequence, err := s.eventstore.LatestSequence(ctx, factory)
|
||||
logging.OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to query latest sequence")
|
||||
var processedSequence uint64
|
||||
for _, filter := range query.Filters {
|
||||
if filter.GetField() == models.Field_LatestSequence {
|
||||
processedSequence = filter.GetValue().(uint64)
|
||||
}
|
||||
}
|
||||
if sequence != 0 && processedSequence == sequence {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
query.Limit = s.QueryLimit()
|
||||
return s.eventstore.FilterEvents(ctx, query)
|
||||
}
|
||||
@@ -169,7 +158,7 @@ func (s *spooledHandler) lock(ctx context.Context, errs chan<- error, workerID s
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-renewTimer:
|
||||
err := s.locker.Renew(workerID, s.ViewModel(), s.LockDuration())
|
||||
err := s.locker.Renew(workerID, s.ViewModel(), systemID, s.LockDuration())
|
||||
firstLock.Do(func() {
|
||||
locked <- err == nil
|
||||
})
|
||||
@@ -190,16 +179,17 @@ func (s *spooledHandler) lock(ctx context.Context, errs chan<- error, workerID s
|
||||
}
|
||||
|
||||
func HandleError(event *models.Event, failedErr error,
|
||||
latestFailedEvent func(sequence uint64) (*repository.FailedEvent, error),
|
||||
latestFailedEvent func(sequence uint64, instanceID string) (*repository.FailedEvent, error),
|
||||
processFailedEvent func(*repository.FailedEvent) error,
|
||||
processSequence func(*models.Event) error,
|
||||
errorCountUntilSkip uint64) error {
|
||||
failedEvent, err := latestFailedEvent(event.Sequence)
|
||||
failedEvent, err := latestFailedEvent(event.Sequence, event.InstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
failedEvent.FailureCount++
|
||||
failedEvent.ErrMsg = failedErr.Error()
|
||||
failedEvent.InstanceID = event.InstanceID
|
||||
err = processFailedEvent(failedEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -3,17 +3,18 @@ package spooler
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler/mock"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
type testHandler struct {
|
||||
@@ -30,7 +31,7 @@ func (h *testHandler) AggregateTypes() []models.AggregateType {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *testHandler) CurrentSequence() (uint64, error) {
|
||||
func (h *testHandler) CurrentSequence(instanceID string) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
@@ -376,8 +377,8 @@ func newTestLocker(t *testing.T, lockerID, viewName string) *testLocker {
|
||||
|
||||
func (l *testLocker) expectRenew(t *testing.T, err error, waitTime time.Duration) *testLocker {
|
||||
t.Helper()
|
||||
l.mock.EXPECT().Renew(gomock.Any(), l.viewName, gomock.Any()).DoAndReturn(
|
||||
func(_, _ string, gotten time.Duration) error {
|
||||
l.mock.EXPECT().Renew(gomock.Any(), l.viewName, gomock.Any(), gomock.Any()).DoAndReturn(
|
||||
func(_, _, _ string, gotten time.Duration) error {
|
||||
t.Helper()
|
||||
if waitTime-gotten != 0 {
|
||||
t.Errorf("expected waittime %v got %v", waitTime, gotten)
|
||||
@@ -396,7 +397,7 @@ func TestHandleError(t *testing.T) {
|
||||
type args struct {
|
||||
event *models.Event
|
||||
failedErr error
|
||||
latestFailedEvent func(sequence uint64) (*repository.FailedEvent, error)
|
||||
latestFailedEvent func(sequence uint64, instanceID string) (*repository.FailedEvent, error)
|
||||
errorCountUntilSkip uint64
|
||||
}
|
||||
type res struct {
|
||||
@@ -413,12 +414,13 @@ func TestHandleError(t *testing.T) {
|
||||
args: args{
|
||||
event: &models.Event{Sequence: 30000000},
|
||||
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
||||
latestFailedEvent: func(s uint64) (*repository.FailedEvent, error) {
|
||||
latestFailedEvent: func(s uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||
return &repository.FailedEvent{
|
||||
ErrMsg: "blub",
|
||||
FailedSequence: s - 1,
|
||||
FailureCount: 6,
|
||||
ViewName: "super.table",
|
||||
InstanceID: instanceID,
|
||||
}, nil
|
||||
},
|
||||
errorCountUntilSkip: 5,
|
||||
@@ -432,12 +434,13 @@ func TestHandleError(t *testing.T) {
|
||||
args: args{
|
||||
event: &models.Event{Sequence: 30000000},
|
||||
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
||||
latestFailedEvent: func(s uint64) (*repository.FailedEvent, error) {
|
||||
latestFailedEvent: func(s uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||
return &repository.FailedEvent{
|
||||
ErrMsg: "blub",
|
||||
FailedSequence: s - 1,
|
||||
FailureCount: 5,
|
||||
ViewName: "super.table",
|
||||
InstanceID: instanceID,
|
||||
}, nil
|
||||
},
|
||||
errorCountUntilSkip: 6,
|
||||
@@ -451,12 +454,13 @@ func TestHandleError(t *testing.T) {
|
||||
args: args{
|
||||
event: &models.Event{Sequence: 30000000},
|
||||
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
||||
latestFailedEvent: func(s uint64) (*repository.FailedEvent, error) {
|
||||
latestFailedEvent: func(s uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||
return &repository.FailedEvent{
|
||||
ErrMsg: "blub",
|
||||
FailedSequence: s - 1,
|
||||
FailureCount: 3,
|
||||
ViewName: "super.table",
|
||||
InstanceID: instanceID,
|
||||
}, nil
|
||||
},
|
||||
errorCountUntilSkip: 5,
|
||||
|
||||
Reference in New Issue
Block a user