feat: handle instanceID in projections (#3442)

* feat: handle instanceID in projections

* rename functions

* fix key lock

* fix import
This commit is contained in:
Livio Amstutz
2022-04-19 08:26:12 +02:00
committed by GitHub
parent c25d853820
commit 1305c14e49
120 changed files with 2078 additions and 1209 deletions

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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,