Skip to content

Commit c04c542

Browse files
Merge pull request #264 from coinbase/patrick/inactive-reconciliation-override
[reconciler] Inactive Reconciliation Bypass
2 parents 3dbb551 + caa08d1 commit c04c542

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

mocks/reconciler/helper.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

reconciler/reconciler.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,13 @@ func (r *Reconciler) reconcileInactiveAccounts( // nolint:gocognit
837837
nextValidIndex = nextAcct.LastCheck.Index + r.inactiveFrequency
838838
}
839839

840-
if nextValidIndex <= head.Index {
840+
if nextValidIndex <= head.Index ||
841+
r.helper.ForceInactiveReconciliation(
842+
ctx,
843+
nextAcct.Entry.Account,
844+
nextAcct.Entry.Currency,
845+
nextAcct.LastCheck,
846+
) {
841847
r.inactiveQueue = r.inactiveQueue[1:]
842848
r.inactiveQueueMutex.Unlock()
843849

reconciler/reconciler_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3267,3 +3267,109 @@ func TestPruningRaceConditionInactive(t *testing.T) {
32673267
mtxn2.AssertExpectations(t)
32683268
mtxn3.AssertExpectations(t)
32693269
}
3270+
3271+
func TestReconcile_SuccessOnlyInactiveOverride(t *testing.T) {
3272+
var (
3273+
block = &types.BlockIdentifier{
3274+
Hash: "block 1",
3275+
Index: 1,
3276+
}
3277+
accountCurrency = &types.AccountCurrency{
3278+
Account: &types.AccountIdentifier{
3279+
Address: "addr 1",
3280+
},
3281+
Currency: &types.Currency{
3282+
Symbol: "BTC",
3283+
Decimals: 8,
3284+
},
3285+
}
3286+
)
3287+
3288+
mockHelper := &mocks.Helper{}
3289+
mockHandler := &mocks.Handler{}
3290+
opts := []Option{
3291+
WithActiveConcurrency(0),
3292+
WithInactiveConcurrency(1),
3293+
WithSeenAccounts([]*types.AccountCurrency{accountCurrency}),
3294+
WithDebugLogging(),
3295+
WithInactiveFrequency(10),
3296+
WithLookupBalanceByBlock(),
3297+
}
3298+
r := New(
3299+
mockHelper,
3300+
mockHandler,
3301+
nil,
3302+
opts...,
3303+
)
3304+
ctx := context.Background()
3305+
ctx, cancel := context.WithCancel(ctx)
3306+
3307+
// Reconcile initially
3308+
mtxn := &mockDatabase.Transaction{}
3309+
mtxn.On("Discard", mock.Anything).Once()
3310+
mockHelper.On("DatabaseTransaction", mock.Anything).Return(mtxn).Once()
3311+
mockHelper.On("CurrentBlock", mock.Anything, mtxn).Return(block, nil).Once()
3312+
mtxn2 := &mockDatabase.Transaction{}
3313+
mtxn2.On(
3314+
"Discard",
3315+
mock.Anything,
3316+
).Once()
3317+
mockHelper.On("DatabaseTransaction", mock.Anything).Return(mtxn2).Once()
3318+
mockReconcilerCalls(
3319+
mockHelper,
3320+
mockHandler,
3321+
mtxn2,
3322+
true,
3323+
accountCurrency,
3324+
"100",
3325+
"100",
3326+
block,
3327+
block,
3328+
true,
3329+
InactiveReconciliation,
3330+
nil,
3331+
false,
3332+
false,
3333+
)
3334+
3335+
// Force Rreconciliation eventhough not required
3336+
mtxn3 := &mockDatabase.Transaction{}
3337+
mtxn3.On("Discard", mock.Anything).Once()
3338+
mockHelper.On("DatabaseTransaction", mock.Anything).Return(mtxn3).Once()
3339+
mockHelper.On("CurrentBlock", mock.Anything, mtxn3).Return(block, nil).Once()
3340+
3341+
mtxn4 := &mockDatabase.Transaction{}
3342+
mtxn4.On("Discard", mock.Anything).Run(
3343+
func(args mock.Arguments) {
3344+
cancel()
3345+
},
3346+
).Once()
3347+
mockHelper.On("DatabaseTransaction", mock.Anything).Return(mtxn4).Once()
3348+
mockHelper.On(
3349+
"ForceInactiveReconciliation",
3350+
mock.Anything,
3351+
accountCurrency.Account,
3352+
accountCurrency.Currency,
3353+
block,
3354+
).Return(
3355+
true,
3356+
).Once()
3357+
mockReconcilerCalls(
3358+
mockHelper,
3359+
mockHandler,
3360+
mtxn4,
3361+
true,
3362+
accountCurrency,
3363+
"100",
3364+
"100",
3365+
block,
3366+
block,
3367+
true,
3368+
InactiveReconciliation,
3369+
nil,
3370+
false,
3371+
false,
3372+
)
3373+
err := r.Reconcile(ctx)
3374+
assert.Contains(t, context.Canceled.Error(), err.Error())
3375+
}

reconciler/types.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,19 @@ type Helper interface {
168168
currency *types.Currency,
169169
index int64,
170170
) error
171+
172+
// ForceInactiveReconciliation is invoked by the
173+
// inactive reconciler when the next account to
174+
// reconcile has been checked within the configured
175+
// inactive reconciliation frequency. This allows
176+
// the helper to dynamically force inactive reconciliation
177+
// when desired (i.e. when at tip).
178+
ForceInactiveReconciliation(
179+
ctx context.Context,
180+
account *types.AccountIdentifier,
181+
currency *types.Currency,
182+
lastCheck *types.BlockIdentifier,
183+
) bool
171184
}
172185

173186
// Handler is called by Reconciler after a reconciliation

0 commit comments

Comments
 (0)