08c9d745f1
Previously, the node events chore would select based on the earliest created_at. However, if for some reason this batch fails, it would still be the next item to select. If there is a consistent error, the chore would be stuck retrying the same batch over and over. Now instead GetNextBatch orders by `last_attempted NULLS FIRST ASC, created_at ASC`. If a batch fails during Notify, last_attempted is updated so we can move on to a new batch if one exists. Change-Id: Ia8458e05ac358d85b2f2c6d690f3d607d631be61
244 lines
8.1 KiB
Go
244 lines
8.1 KiB
Go
// Copyright (C) 2022 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package satellitedb_test
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"storj.io/common/testcontext"
|
|
"storj.io/common/uuid"
|
|
"storj.io/storj/private/teststorj"
|
|
"storj.io/storj/satellite"
|
|
"storj.io/storj/satellite/nodeevents"
|
|
"storj.io/storj/satellite/satellitedb/satellitedbtest"
|
|
)
|
|
|
|
func TestNodeEvents(t *testing.T) {
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
|
testID := teststorj.NodeIDFromString("test")
|
|
testEmail := "test@storj.test"
|
|
eventType := nodeevents.Disqualified
|
|
|
|
neFromInsert, err := db.NodeEvents().Insert(ctx, testEmail, testID, eventType)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, neFromInsert.ID)
|
|
require.Equal(t, testID, neFromInsert.NodeID)
|
|
require.Equal(t, testEmail, neFromInsert.Email)
|
|
require.Equal(t, eventType, neFromInsert.Event)
|
|
require.NotNil(t, neFromInsert.CreatedAt)
|
|
require.Nil(t, neFromInsert.EmailSent)
|
|
|
|
neFromGet, err := db.NodeEvents().GetLatestByEmailAndEvent(ctx, neFromInsert.Email, neFromInsert.Event)
|
|
require.NoError(t, err)
|
|
require.Equal(t, neFromInsert, neFromGet)
|
|
})
|
|
}
|
|
|
|
func TestNodeEventsUpdateEmailSent(t *testing.T) {
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
|
testID1 := teststorj.NodeIDFromString("test1")
|
|
testID2 := teststorj.NodeIDFromString("test2")
|
|
testEmail1 := "test1@storj.test"
|
|
eventType := nodeevents.Disqualified
|
|
|
|
// Insert into node events
|
|
event1, err := db.NodeEvents().Insert(ctx, testEmail1, testID1, eventType)
|
|
require.NoError(t, err)
|
|
|
|
event2, err := db.NodeEvents().Insert(ctx, testEmail1, testID2, eventType)
|
|
require.NoError(t, err)
|
|
|
|
// GetNextBatch should get them.
|
|
events, err := db.NodeEvents().GetNextBatch(ctx, time.Now())
|
|
require.NoError(t, err)
|
|
|
|
var foundEvent1, foundEvent2 bool
|
|
for _, ne := range events {
|
|
switch ne.NodeID {
|
|
case event1.NodeID:
|
|
foundEvent1 = true
|
|
case event2.NodeID:
|
|
foundEvent2 = true
|
|
default:
|
|
}
|
|
}
|
|
require.True(t, foundEvent1)
|
|
require.True(t, foundEvent2)
|
|
|
|
// Update email sent
|
|
require.NoError(t, db.NodeEvents().UpdateEmailSent(ctx, []uuid.UUID{event1.ID, event2.ID}, time.Now()))
|
|
|
|
// They shouldn't be found since email_sent should have been updated.
|
|
// It's an indirect way of checking. Not the best. We would need to add a new Read method
|
|
// to get specific rows by ID.
|
|
events, err = db.NodeEvents().GetNextBatch(ctx, time.Now())
|
|
require.NoError(t, err)
|
|
require.Len(t, events, 0)
|
|
})
|
|
}
|
|
|
|
func TestNodeEventsUpdateLastAttempted(t *testing.T) {
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
|
testID1 := teststorj.NodeIDFromString("test1")
|
|
testID2 := teststorj.NodeIDFromString("test2")
|
|
testEmail1 := "test1@storj.test"
|
|
eventType := nodeevents.Disqualified
|
|
|
|
event1, err := db.NodeEvents().Insert(ctx, testEmail1, testID1, eventType)
|
|
require.NoError(t, err)
|
|
|
|
event1, err = db.NodeEvents().GetByID(ctx, event1.ID)
|
|
require.NoError(t, err)
|
|
require.Nil(t, event1.LastAttempted)
|
|
|
|
event2, err := db.NodeEvents().Insert(ctx, testEmail1, testID2, eventType)
|
|
require.NoError(t, err)
|
|
|
|
event2, err = db.NodeEvents().GetByID(ctx, event2.ID)
|
|
require.NoError(t, err)
|
|
require.Nil(t, event2.LastAttempted)
|
|
|
|
require.NoError(t, db.NodeEvents().UpdateLastAttempted(ctx, []uuid.UUID{event1.ID, event2.ID}, time.Now()))
|
|
|
|
event1, err = db.NodeEvents().GetByID(ctx, event1.ID)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, event1.LastAttempted)
|
|
|
|
event2, err = db.NodeEvents().GetByID(ctx, event2.ID)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, event2.LastAttempted)
|
|
})
|
|
}
|
|
|
|
func TestNodeEventsGetByID(t *testing.T) {
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
|
testID1 := teststorj.NodeIDFromString("test1")
|
|
testID2 := teststorj.NodeIDFromString("test2")
|
|
testEmail1 := "test1@storj.test"
|
|
testEmail2 := "test2@storj.test"
|
|
|
|
eventType := nodeevents.Disqualified
|
|
|
|
event1, err := db.NodeEvents().Insert(ctx, testEmail1, testID1, eventType)
|
|
require.NoError(t, err)
|
|
|
|
event2, err := db.NodeEvents().Insert(ctx, testEmail2, testID2, eventType)
|
|
require.NoError(t, err)
|
|
|
|
res, err := db.NodeEvents().GetByID(ctx, event1.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, event1.Email, res.Email)
|
|
require.Equal(t, event1.CreatedAt, res.CreatedAt)
|
|
require.Equal(t, event1.Event, res.Event)
|
|
|
|
res, err = db.NodeEvents().GetByID(ctx, event2.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, event2.Email, res.Email)
|
|
require.Equal(t, event2.CreatedAt, res.CreatedAt)
|
|
require.Equal(t, event2.Event, res.Event)
|
|
})
|
|
}
|
|
|
|
func TestNodeEventsGetNextBatch(t *testing.T) {
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
|
testID1 := teststorj.NodeIDFromString("test1")
|
|
testID2 := teststorj.NodeIDFromString("test2")
|
|
testEmail1 := "test1@storj.test"
|
|
testEmail2 := "test2@storj.test"
|
|
|
|
eventType := nodeevents.Disqualified
|
|
|
|
event1, err := db.NodeEvents().Insert(ctx, testEmail1, testID1, eventType)
|
|
require.NoError(t, err)
|
|
|
|
// insert one event with same email and event type, but with different node ID. It should be selected.
|
|
event2, err := db.NodeEvents().Insert(ctx, testEmail1, testID2, eventType)
|
|
require.NoError(t, err)
|
|
|
|
// insert one event with same email and event type, but email_sent is not null. Should not be selected.
|
|
event3, err := db.NodeEvents().Insert(ctx, testEmail1, testID1, eventType)
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, db.NodeEvents().UpdateEmailSent(ctx, []uuid.UUID{event3.ID}, time.Now()))
|
|
|
|
// insert one event with same email, but different type. Should not be selected.
|
|
_, err = db.NodeEvents().Insert(ctx, testEmail1, testID1, nodeevents.BelowMinVersion)
|
|
require.NoError(t, err)
|
|
|
|
// insert one event with same event type, but different email. Should not be selected.
|
|
_, err = db.NodeEvents().Insert(ctx, testEmail2, testID1, eventType)
|
|
require.NoError(t, err)
|
|
|
|
batch, err := db.NodeEvents().GetNextBatch(ctx, time.Now())
|
|
require.NoError(t, err)
|
|
require.Len(t, batch, 2)
|
|
|
|
var foundEvent1, foundEvent2 bool
|
|
for _, ne := range batch {
|
|
switch ne.NodeID {
|
|
case event1.NodeID:
|
|
foundEvent1 = true
|
|
case event2.NodeID:
|
|
foundEvent2 = true
|
|
default:
|
|
}
|
|
}
|
|
require.True(t, foundEvent1)
|
|
require.True(t, foundEvent2)
|
|
})
|
|
}
|
|
|
|
func TestNodeEventsGetNextBatchSelectionOrder(t *testing.T) {
|
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
|
id0 := teststorj.NodeIDFromString("test0")
|
|
id1 := teststorj.NodeIDFromString("test1")
|
|
id2 := teststorj.NodeIDFromString("test2")
|
|
id3 := teststorj.NodeIDFromString("test3")
|
|
|
|
email0 := "test0@storj.test"
|
|
email1 := "test1@storj.test"
|
|
email2 := "test2@storj.test"
|
|
email3 := "test3@storj.test"
|
|
|
|
eventType := nodeevents.Disqualified
|
|
|
|
// GetNextBatch orders by last_attempted, created_at asc
|
|
// expected selection order:
|
|
// 1. insert0: last_attempted = nil, created_at = earliest
|
|
// 2. insert3: last_attempted = nil, created_at = 3rd earliest
|
|
// 3. insert2: last_attempted != nil, created_at = 4th earliest
|
|
// 4. insert1: last_attempted later than insert2, created_at = 2nd earliest
|
|
expectedOrder := []string{
|
|
email0, email3, email2, email1,
|
|
}
|
|
|
|
_, err := db.NodeEvents().Insert(ctx, email0, id0, eventType)
|
|
require.NoError(t, err)
|
|
|
|
insert1, err := db.NodeEvents().Insert(ctx, email1, id1, eventType)
|
|
require.NoError(t, err)
|
|
require.NoError(t, err)
|
|
require.NoError(t, db.NodeEvents().UpdateLastAttempted(ctx, []uuid.UUID{insert1.ID}, time.Now().Add(5*time.Minute)))
|
|
|
|
insert2, err := db.NodeEvents().Insert(ctx, email2, id2, eventType)
|
|
require.NoError(t, err)
|
|
require.NoError(t, err)
|
|
require.NoError(t, db.NodeEvents().UpdateLastAttempted(ctx, []uuid.UUID{insert2.ID}, time.Now()))
|
|
|
|
_, err = db.NodeEvents().Insert(ctx, email3, id3, eventType)
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < 4; i++ {
|
|
e, err := db.NodeEvents().GetNextBatch(ctx, time.Now())
|
|
require.NoError(t, err)
|
|
require.Equal(t, expectedOrder[i], e[0].Email)
|
|
|
|
require.NoError(t, db.NodeEvents().UpdateEmailSent(ctx, []uuid.UUID{e[0].ID}, time.Now()))
|
|
}
|
|
})
|
|
}
|