mirror of
https://github.com/matrix-org/dendrite.git
synced 2026-01-21 13:03:09 -06:00
Handle async send success/fail cases
This commit is contained in:
parent
e26d07c779
commit
9dbfcd9e06
|
|
@ -164,7 +164,7 @@ func (a *FederationInternalAPI) doRequestIfNotBackingOffOrBlacklisted(
|
||||||
RetryAfter: retryAfter,
|
RetryAfter: retryAfter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stats.Success()
|
stats.Success(false)
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func (r *FederationInternalAPI) PerformDirectoryLookup(
|
||||||
}
|
}
|
||||||
response.RoomID = dir.RoomID
|
response.RoomID = dir.RoomID
|
||||||
response.ServerNames = dir.Servers
|
response.ServerNames = dir.Servers
|
||||||
r.statistics.ForServer(request.ServerName).Success()
|
r.statistics.ForServer(request.ServerName).Success(false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ func (r *FederationInternalAPI) performJoinUsingServer(
|
||||||
r.statistics.ForServer(serverName).Failure()
|
r.statistics.ForServer(serverName).Failure()
|
||||||
return fmt.Errorf("r.federation.MakeJoin: %w", err)
|
return fmt.Errorf("r.federation.MakeJoin: %w", err)
|
||||||
}
|
}
|
||||||
r.statistics.ForServer(serverName).Success()
|
r.statistics.ForServer(serverName).Success(false)
|
||||||
|
|
||||||
// Set all the fields to be what they should be, this should be a no-op
|
// Set all the fields to be what they should be, this should be a no-op
|
||||||
// but it's possible that the remote server returned us something "odd"
|
// but it's possible that the remote server returned us something "odd"
|
||||||
|
|
@ -221,7 +221,7 @@ func (r *FederationInternalAPI) performJoinUsingServer(
|
||||||
r.statistics.ForServer(serverName).Failure()
|
r.statistics.ForServer(serverName).Failure()
|
||||||
return fmt.Errorf("r.federation.SendJoin: %w", err)
|
return fmt.Errorf("r.federation.SendJoin: %w", err)
|
||||||
}
|
}
|
||||||
r.statistics.ForServer(serverName).Success()
|
r.statistics.ForServer(serverName).Success(false)
|
||||||
|
|
||||||
// If the remote server returned an event in the "event" key of
|
// If the remote server returned an event in the "event" key of
|
||||||
// the send_join request then we should use that instead. It may
|
// the send_join request then we should use that instead. It may
|
||||||
|
|
@ -451,7 +451,7 @@ func (r *FederationInternalAPI) performOutboundPeekUsingServer(
|
||||||
r.statistics.ForServer(serverName).Failure()
|
r.statistics.ForServer(serverName).Failure()
|
||||||
return fmt.Errorf("r.federation.Peek: %w", err)
|
return fmt.Errorf("r.federation.Peek: %w", err)
|
||||||
}
|
}
|
||||||
r.statistics.ForServer(serverName).Success()
|
r.statistics.ForServer(serverName).Success(false)
|
||||||
|
|
||||||
// Work out if we support the room version that has been supplied in
|
// Work out if we support the room version that has been supplied in
|
||||||
// the peek response.
|
// the peek response.
|
||||||
|
|
@ -588,7 +588,7 @@ func (r *FederationInternalAPI) PerformLeave(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
r.statistics.ForServer(serverName).Success()
|
r.statistics.ForServer(serverName).Success(false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,7 @@ func (oq *destinationQueue) backgroundSend() {
|
||||||
|
|
||||||
// If we have pending PDUs or EDUs then construct a transaction.
|
// If we have pending PDUs or EDUs then construct a transaction.
|
||||||
// Try sending the next transaction and see what happens.
|
// Try sending the next transaction and see what happens.
|
||||||
terr := oq.nextTransaction(toSendPDUs, toSendEDUs)
|
terr, asyncSuccess := oq.nextTransaction(toSendPDUs, toSendEDUs)
|
||||||
if terr != nil {
|
if terr != nil {
|
||||||
// We failed to send the transaction. Mark it as a failure.
|
// We failed to send the transaction. Mark it as a failure.
|
||||||
_, blacklisted := oq.statistics.Failure()
|
_, blacklisted := oq.statistics.Failure()
|
||||||
|
|
@ -367,18 +367,19 @@ func (oq *destinationQueue) backgroundSend() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
oq.handleTransactionSuccess(pduCount, eduCount)
|
oq.handleTransactionSuccess(pduCount, eduCount, asyncSuccess)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextTransaction creates a new transaction from the pending event
|
// nextTransaction creates a new transaction from the pending event
|
||||||
// queue and sends it.
|
// queue and sends it.
|
||||||
// Returns an error if the transaction wasn't sent.
|
// Returns an error if the transaction wasn't sent. And whether the success
|
||||||
|
// was to an async mailserver or not.
|
||||||
func (oq *destinationQueue) nextTransaction(
|
func (oq *destinationQueue) nextTransaction(
|
||||||
pdus []*queuedPDU,
|
pdus []*queuedPDU,
|
||||||
edus []*queuedEDU,
|
edus []*queuedEDU,
|
||||||
) error {
|
) (err error, asyncSuccess bool) {
|
||||||
// Create the transaction.
|
// Create the transaction.
|
||||||
t, pduReceipts, eduReceipts := oq.createTransaction(pdus, edus)
|
t, pduReceipts, eduReceipts := oq.createTransaction(pdus, edus)
|
||||||
logrus.WithField("server_name", oq.destination).Debugf("Sending transaction %q containing %d PDUs, %d EDUs", t.TransactionID, len(t.PDUs), len(t.EDUs))
|
logrus.WithField("server_name", oq.destination).Debugf("Sending transaction %q containing %d PDUs, %d EDUs", t.TransactionID, len(t.PDUs), len(t.EDUs))
|
||||||
|
|
@ -387,21 +388,22 @@ func (oq *destinationQueue) nextTransaction(
|
||||||
ctx, cancel := context.WithTimeout(oq.process.Context(), time.Minute*5)
|
ctx, cancel := context.WithTimeout(oq.process.Context(), time.Minute*5)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
var err error
|
|
||||||
mailservers := oq.statistics.KnownMailservers()
|
mailservers := oq.statistics.KnownMailservers()
|
||||||
if oq.statistics.AssumedOffline() && len(mailservers) > 0 {
|
if oq.statistics.AssumedOffline() && len(mailservers) > 0 {
|
||||||
// TODO : how to pass through actual userID here?!?!?!?!
|
// TODO : how to pass through actual userID here?!?!?!?!
|
||||||
userID, _ := gomatrixserverlib.NewUserID("@:"+string(oq.origin), false)
|
userID, err := gomatrixserverlib.NewUserID("@user:"+string(oq.origin), false)
|
||||||
anySuccess := false
|
if err != nil {
|
||||||
|
return err, false
|
||||||
|
}
|
||||||
for _, mailserver := range mailservers {
|
for _, mailserver := range mailservers {
|
||||||
_, asyncErr := oq.client.SendAsyncTransaction(ctx, *userID, t, mailserver)
|
_, asyncErr := oq.client.SendAsyncTransaction(ctx, *userID, t, mailserver)
|
||||||
if asyncErr != nil {
|
if asyncErr != nil {
|
||||||
err = asyncErr
|
err = asyncErr
|
||||||
} else {
|
} else {
|
||||||
anySuccess = true
|
asyncSuccess = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if anySuccess {
|
if asyncSuccess {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -426,7 +428,7 @@ func (oq *destinationQueue) nextTransaction(
|
||||||
oq.transactionIDMutex.Lock()
|
oq.transactionIDMutex.Lock()
|
||||||
oq.transactionID = ""
|
oq.transactionID = ""
|
||||||
oq.transactionIDMutex.Unlock()
|
oq.transactionIDMutex.Unlock()
|
||||||
return nil
|
return nil, asyncSuccess
|
||||||
case gomatrix.HTTPError:
|
case gomatrix.HTTPError:
|
||||||
// Report that we failed to send the transaction and we
|
// Report that we failed to send the transaction and we
|
||||||
// will retry again, subject to backoff.
|
// will retry again, subject to backoff.
|
||||||
|
|
@ -436,13 +438,13 @@ func (oq *destinationQueue) nextTransaction(
|
||||||
// to a 400-ish error
|
// to a 400-ish error
|
||||||
code := errResponse.Code
|
code := errResponse.Code
|
||||||
logrus.Debug("Transaction failed with HTTP", code)
|
logrus.Debug("Transaction failed with HTTP", code)
|
||||||
return err
|
return err, false
|
||||||
default:
|
default:
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"destination": oq.destination,
|
"destination": oq.destination,
|
||||||
logrus.ErrorKey: err,
|
logrus.ErrorKey: err,
|
||||||
}).Debugf("Failed to send transaction %q", t.TransactionID)
|
}).Debugf("Failed to send transaction %q", t.TransactionID)
|
||||||
return err
|
return err, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -529,10 +531,10 @@ func (oq *destinationQueue) blacklistDestination() {
|
||||||
|
|
||||||
// handleTransactionSuccess updates the cached event queues as well as the success and
|
// handleTransactionSuccess updates the cached event queues as well as the success and
|
||||||
// backoff information for this server.
|
// backoff information for this server.
|
||||||
func (oq *destinationQueue) handleTransactionSuccess(pduCount int, eduCount int) {
|
func (oq *destinationQueue) handleTransactionSuccess(pduCount int, eduCount int, asyncSuccess bool) {
|
||||||
// If we successfully sent the transaction then clear out
|
// If we successfully sent the transaction then clear out
|
||||||
// the pending events and EDUs, and wipe our transaction ID.
|
// the pending events and EDUs, and wipe our transaction ID.
|
||||||
oq.statistics.Success()
|
oq.statistics.Success(asyncSuccess)
|
||||||
oq.pendingMutex.Lock()
|
oq.pendingMutex.Lock()
|
||||||
defer oq.pendingMutex.Unlock()
|
defer oq.pendingMutex.Unlock()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ func createDatabase() storage.Database {
|
||||||
pendingEDUs: make(map[*shared.Receipt]*gomatrixserverlib.EDU),
|
pendingEDUs: make(map[*shared.Receipt]*gomatrixserverlib.EDU),
|
||||||
associatedPDUs: make(map[gomatrixserverlib.ServerName]map[*shared.Receipt]struct{}),
|
associatedPDUs: make(map[gomatrixserverlib.ServerName]map[*shared.Receipt]struct{}),
|
||||||
associatedEDUs: make(map[gomatrixserverlib.ServerName]map[*shared.Receipt]struct{}),
|
associatedEDUs: make(map[gomatrixserverlib.ServerName]map[*shared.Receipt]struct{}),
|
||||||
|
mailservers: make(map[gomatrixserverlib.ServerName][]gomatrixserverlib.ServerName),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,6 +90,7 @@ type fakeDatabase struct {
|
||||||
pendingEDUs map[*shared.Receipt]*gomatrixserverlib.EDU
|
pendingEDUs map[*shared.Receipt]*gomatrixserverlib.EDU
|
||||||
associatedPDUs map[gomatrixserverlib.ServerName]map[*shared.Receipt]struct{}
|
associatedPDUs map[gomatrixserverlib.ServerName]map[*shared.Receipt]struct{}
|
||||||
associatedEDUs map[gomatrixserverlib.ServerName]map[*shared.Receipt]struct{}
|
associatedEDUs map[gomatrixserverlib.ServerName]map[*shared.Receipt]struct{}
|
||||||
|
mailservers map[gomatrixserverlib.ServerName][]gomatrixserverlib.ServerName
|
||||||
}
|
}
|
||||||
|
|
||||||
var nidMutex sync.Mutex
|
var nidMutex sync.Mutex
|
||||||
|
|
@ -340,7 +342,36 @@ func (d *fakeDatabase) IsServerAssumedOffline(serverName gomatrixserverlib.Serve
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *fakeDatabase) GetMailserversForServer(serverName gomatrixserverlib.ServerName) ([]gomatrixserverlib.ServerName, error) {
|
func (d *fakeDatabase) GetMailserversForServer(serverName gomatrixserverlib.ServerName) ([]gomatrixserverlib.ServerName, error) {
|
||||||
return []gomatrixserverlib.ServerName{}, nil
|
d.dbMutex.Lock()
|
||||||
|
defer d.dbMutex.Unlock()
|
||||||
|
|
||||||
|
knownMailservers := []gomatrixserverlib.ServerName{}
|
||||||
|
if mailservers, ok := d.mailservers[serverName]; ok {
|
||||||
|
knownMailservers = mailservers
|
||||||
|
}
|
||||||
|
|
||||||
|
return knownMailservers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fakeDatabase) AddMailserversForServer(serverName gomatrixserverlib.ServerName, mailservers []gomatrixserverlib.ServerName) error {
|
||||||
|
d.dbMutex.Lock()
|
||||||
|
defer d.dbMutex.Unlock()
|
||||||
|
|
||||||
|
if knownMailservers, ok := d.mailservers[serverName]; ok {
|
||||||
|
for _, mailserver := range mailservers {
|
||||||
|
alreadyKnown := false
|
||||||
|
for _, knownMailserver := range knownMailservers {
|
||||||
|
if mailserver == knownMailserver {
|
||||||
|
alreadyKnown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !alreadyKnown {
|
||||||
|
d.mailservers[serverName] = append(d.mailservers[serverName], mailserver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type stubFederationRoomServerAPI struct {
|
type stubFederationRoomServerAPI struct {
|
||||||
|
|
@ -354,8 +385,10 @@ func (r *stubFederationRoomServerAPI) QueryServerBannedFromRoom(ctx context.Cont
|
||||||
|
|
||||||
type stubFederationClient struct {
|
type stubFederationClient struct {
|
||||||
api.FederationClient
|
api.FederationClient
|
||||||
shouldTxSucceed bool
|
shouldTxSucceed bool
|
||||||
txCount atomic.Uint32
|
shouldTxAsyncSucceed bool
|
||||||
|
txCount atomic.Uint32
|
||||||
|
txAsyncCount atomic.Uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *stubFederationClient) SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res gomatrixserverlib.RespSend, err error) {
|
func (f *stubFederationClient) SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res gomatrixserverlib.RespSend, err error) {
|
||||||
|
|
@ -368,6 +401,16 @@ func (f *stubFederationClient) SendTransaction(ctx context.Context, t gomatrixse
|
||||||
return gomatrixserverlib.RespSend{}, result
|
return gomatrixserverlib.RespSend{}, result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *stubFederationClient) SendAsyncTransaction(ctx context.Context, u gomatrixserverlib.UserID, t gomatrixserverlib.Transaction, forwardingServer gomatrixserverlib.ServerName) (res gomatrixserverlib.EmptyResp, err error) {
|
||||||
|
var result error
|
||||||
|
if !f.shouldTxAsyncSucceed {
|
||||||
|
result = fmt.Errorf("async transaction failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
f.txAsyncCount.Add(1)
|
||||||
|
return gomatrixserverlib.EmptyResp{}, result
|
||||||
|
}
|
||||||
|
|
||||||
func mustCreatePDU(t *testing.T) *gomatrixserverlib.HeaderedEvent {
|
func mustCreatePDU(t *testing.T) *gomatrixserverlib.HeaderedEvent {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
content := `{"type":"m.room.message"}`
|
content := `{"type":"m.room.message"}`
|
||||||
|
|
@ -383,12 +426,14 @@ func mustCreateEDU(t *testing.T) *gomatrixserverlib.EDU {
|
||||||
return &gomatrixserverlib.EDU{Type: gomatrixserverlib.MTyping}
|
return &gomatrixserverlib.EDU{Type: gomatrixserverlib.MTyping}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSetup(failuresUntilBlacklist uint32, failuresUntilAssumedOffline uint32, shouldTxSucceed bool, t *testing.T, dbType test.DBType, realDatabase bool) (storage.Database, *stubFederationClient, *OutgoingQueues, *process.ProcessContext, func()) {
|
func testSetup(failuresUntilBlacklist uint32, failuresUntilAssumedOffline uint32, shouldTxSucceed bool, shouldTxAsyncSucceed bool, t *testing.T, dbType test.DBType, realDatabase bool) (storage.Database, *stubFederationClient, *OutgoingQueues, *process.ProcessContext, func()) {
|
||||||
db, processContext, close := mustCreateFederationDatabase(t, dbType, realDatabase)
|
db, processContext, close := mustCreateFederationDatabase(t, dbType, realDatabase)
|
||||||
|
|
||||||
fc := &stubFederationClient{
|
fc := &stubFederationClient{
|
||||||
shouldTxSucceed: shouldTxSucceed,
|
shouldTxSucceed: shouldTxSucceed,
|
||||||
txCount: *atomic.NewUint32(0),
|
shouldTxAsyncSucceed: shouldTxAsyncSucceed,
|
||||||
|
txCount: *atomic.NewUint32(0),
|
||||||
|
txAsyncCount: *atomic.NewUint32(0),
|
||||||
}
|
}
|
||||||
rs := &stubFederationRoomServerAPI{}
|
rs := &stubFederationRoomServerAPI{}
|
||||||
|
|
||||||
|
|
@ -408,7 +453,7 @@ func TestSendPDUOnSuccessRemovedFromDB(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(16)
|
failuresUntilBlacklist := uint32(16)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -437,7 +482,7 @@ func TestSendEDUOnSuccessRemovedFromDB(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(16)
|
failuresUntilBlacklist := uint32(16)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -466,7 +511,7 @@ func TestSendPDUOnFailStoredInDB(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(16)
|
failuresUntilBlacklist := uint32(16)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -496,7 +541,7 @@ func TestSendEDUOnFailStoredInDB(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(16)
|
failuresUntilBlacklist := uint32(16)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -526,7 +571,7 @@ func TestSendPDUAgainDoesntInterruptBackoff(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(16)
|
failuresUntilBlacklist := uint32(16)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -577,7 +622,7 @@ func TestSendEDUAgainDoesntInterruptBackoff(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(16)
|
failuresUntilBlacklist := uint32(16)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -628,7 +673,7 @@ func TestSendPDUMultipleFailuresBlacklisted(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(2)
|
failuresUntilBlacklist := uint32(2)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -660,7 +705,7 @@ func TestSendEDUMultipleFailuresBlacklisted(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(2)
|
failuresUntilBlacklist := uint32(2)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -692,7 +737,7 @@ func TestSendPDUBlacklistedWithPriorExternalFailure(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(2)
|
failuresUntilBlacklist := uint32(2)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -726,7 +771,7 @@ func TestSendEDUBlacklistedWithPriorExternalFailure(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(2)
|
failuresUntilBlacklist := uint32(2)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -760,7 +805,7 @@ func TestRetryServerSendsPDUSuccessfully(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(1)
|
failuresUntilBlacklist := uint32(1)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -811,7 +856,7 @@ func TestRetryServerSendsEDUSuccessfully(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(1)
|
failuresUntilBlacklist := uint32(1)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -865,7 +910,7 @@ func TestSendPDUBatches(t *testing.T) {
|
||||||
|
|
||||||
// test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
// test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
// db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, true, t, dbType, true)
|
// db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, true, t, dbType, true)
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -909,7 +954,7 @@ func TestSendEDUBatches(t *testing.T) {
|
||||||
|
|
||||||
// test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
// test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
// db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, true, t, dbType, true)
|
// db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, true, t, dbType, true)
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -953,7 +998,7 @@ func TestSendPDUAndEDUBatches(t *testing.T) {
|
||||||
|
|
||||||
// test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
// test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
// db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, true, t, dbType, true)
|
// db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, true, t, dbType, true)
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -1004,7 +1049,7 @@ func TestExternalFailureBackoffDoesntStartQueue(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
failuresUntilBlacklist := uint32(16)
|
failuresUntilBlacklist := uint32(16)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, true, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -1042,7 +1087,7 @@ func TestQueueInteractsWithRealDatabasePDUAndEDU(t *testing.T) {
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
destinations := map[gomatrixserverlib.ServerName]struct{}{destination: {}}
|
destinations := map[gomatrixserverlib.ServerName]struct{}{destination: {}}
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, t, dbType, true)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilBlacklist+1, false, false, t, dbType, true)
|
||||||
// NOTE : These defers aren't called if go test is killed so the dbs may not get cleaned up.
|
// NOTE : These defers aren't called if go test is killed so the dbs may not get cleaned up.
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
@ -1108,7 +1153,7 @@ func TestSendPDUMultipleFailuresAssumedOffline(t *testing.T) {
|
||||||
failuresUntilBlacklist := uint32(7)
|
failuresUntilBlacklist := uint32(7)
|
||||||
failuresUntilAssumedOffline := uint32(2)
|
failuresUntilAssumedOffline := uint32(2)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilAssumedOffline, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilAssumedOffline, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -1141,7 +1186,7 @@ func TestSendEDUMultipleFailuresAssumedOffline(t *testing.T) {
|
||||||
failuresUntilBlacklist := uint32(7)
|
failuresUntilBlacklist := uint32(7)
|
||||||
failuresUntilAssumedOffline := uint32(2)
|
failuresUntilAssumedOffline := uint32(2)
|
||||||
destination := gomatrixserverlib.ServerName("remotehost")
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilAssumedOffline, false, t, test.DBTypeSQLite, false)
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilAssumedOffline, false, false, t, test.DBTypeSQLite, false)
|
||||||
defer close()
|
defer close()
|
||||||
defer func() {
|
defer func() {
|
||||||
pc.ShutdownDendrite()
|
pc.ShutdownDendrite()
|
||||||
|
|
@ -1168,3 +1213,81 @@ func TestSendEDUMultipleFailuresAssumedOffline(t *testing.T) {
|
||||||
}
|
}
|
||||||
poll.WaitOn(t, check, poll.WithTimeout(5*time.Second), poll.WithDelay(100*time.Millisecond))
|
poll.WaitOn(t, check, poll.WithTimeout(5*time.Second), poll.WithDelay(100*time.Millisecond))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSendPDUOnAsyncSuccessRemovedFromDB(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
failuresUntilBlacklist := uint32(16)
|
||||||
|
failuresUntilAssumedOffline := uint32(1)
|
||||||
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilAssumedOffline, false, true, t, test.DBTypeSQLite, false)
|
||||||
|
defer close()
|
||||||
|
defer func() {
|
||||||
|
pc.ShutdownDendrite()
|
||||||
|
<-pc.WaitForShutdown()
|
||||||
|
}()
|
||||||
|
|
||||||
|
mailservers := []gomatrixserverlib.ServerName{"mailserver"}
|
||||||
|
queues.statistics.ForServer(destination).AddMailservers(mailservers)
|
||||||
|
|
||||||
|
ev := mustCreatePDU(t)
|
||||||
|
err := queues.SendEvent(ev, "localhost", []gomatrixserverlib.ServerName{destination})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
check := func(log poll.LogT) poll.Result {
|
||||||
|
if fc.txCount.Load() == 1 {
|
||||||
|
if fc.txAsyncCount.Load() == 1 {
|
||||||
|
data, dbErr := db.GetPendingPDUs(pc.Context(), destination, 100)
|
||||||
|
assert.NoError(t, dbErr)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return poll.Success()
|
||||||
|
}
|
||||||
|
return poll.Continue("waiting for event to be removed from database. Currently present PDU: %d", len(data))
|
||||||
|
}
|
||||||
|
return poll.Continue("waiting for more async send attempts before checking database. Currently %d", fc.txAsyncCount.Load())
|
||||||
|
}
|
||||||
|
return poll.Continue("waiting for more send attempts before checking database. Currently %d", fc.txCount.Load())
|
||||||
|
}
|
||||||
|
poll.WaitOn(t, check, poll.WithTimeout(5*time.Second), poll.WithDelay(100*time.Millisecond))
|
||||||
|
|
||||||
|
assumedOffline, _ := db.IsServerAssumedOffline(destination)
|
||||||
|
assert.Equal(t, assumedOffline, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendEDUOnAsyncSuccessRemovedFromDB(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
failuresUntilBlacklist := uint32(16)
|
||||||
|
failuresUntilAssumedOffline := uint32(1)
|
||||||
|
destination := gomatrixserverlib.ServerName("remotehost")
|
||||||
|
db, fc, queues, pc, close := testSetup(failuresUntilBlacklist, failuresUntilAssumedOffline, false, true, t, test.DBTypeSQLite, false)
|
||||||
|
defer close()
|
||||||
|
defer func() {
|
||||||
|
pc.ShutdownDendrite()
|
||||||
|
<-pc.WaitForShutdown()
|
||||||
|
}()
|
||||||
|
|
||||||
|
mailservers := []gomatrixserverlib.ServerName{"mailserver"}
|
||||||
|
queues.statistics.ForServer(destination).AddMailservers(mailservers)
|
||||||
|
|
||||||
|
ev := mustCreateEDU(t)
|
||||||
|
err := queues.SendEDU(ev, "localhost", []gomatrixserverlib.ServerName{destination})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
check := func(log poll.LogT) poll.Result {
|
||||||
|
if fc.txCount.Load() == 1 {
|
||||||
|
if fc.txAsyncCount.Load() == 1 {
|
||||||
|
data, dbErr := db.GetPendingEDUs(pc.Context(), destination, 100)
|
||||||
|
assert.NoError(t, dbErr)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return poll.Success()
|
||||||
|
}
|
||||||
|
return poll.Continue("waiting for event to be removed from database. Currently present EDU: %d", len(data))
|
||||||
|
}
|
||||||
|
return poll.Continue("waiting for more async send attempts before checking database. Currently %d", fc.txAsyncCount.Load())
|
||||||
|
}
|
||||||
|
return poll.Continue("waiting for more send attempts before checking database. Currently %d", fc.txCount.Load())
|
||||||
|
}
|
||||||
|
poll.WaitOn(t, check, poll.WithTimeout(5*time.Second), poll.WithDelay(100*time.Millisecond))
|
||||||
|
|
||||||
|
assumedOffline, _ := db.IsServerAssumedOffline(destination)
|
||||||
|
assert.Equal(t, assumedOffline, true)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -138,13 +138,19 @@ func (s *ServerStatistics) AssignBackoffNotifier(notifier func()) {
|
||||||
// attempt, which increases the sent counter and resets the idle and
|
// attempt, which increases the sent counter and resets the idle and
|
||||||
// failure counters. If a host was blacklisted at this point then
|
// failure counters. If a host was blacklisted at this point then
|
||||||
// we will unblacklist it.
|
// we will unblacklist it.
|
||||||
func (s *ServerStatistics) Success() {
|
// `async` specifies whether the success was to the actual destination
|
||||||
|
// or one of their mailservers.
|
||||||
|
func (s *ServerStatistics) Success(async bool) {
|
||||||
s.cancel()
|
s.cancel()
|
||||||
s.backoffCount.Store(0)
|
s.backoffCount.Store(0)
|
||||||
s.successCounter.Inc()
|
// NOTE : Sending to the final destination vs. a mailserver has
|
||||||
if s.statistics.DB != nil {
|
// slightly different semantics.
|
||||||
if err := s.statistics.DB.RemoveServerFromBlacklist(s.serverName); err != nil {
|
if !async {
|
||||||
logrus.WithError(err).Errorf("Failed to remove %q from blacklist", s.serverName)
|
s.successCounter.Inc()
|
||||||
|
if s.statistics.DB != nil {
|
||||||
|
if err := s.statistics.DB.RemoveServerFromBlacklist(s.serverName); err != nil {
|
||||||
|
logrus.WithError(err).Errorf("Failed to remove %q from blacklist", s.serverName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -265,3 +271,31 @@ func (s *ServerStatistics) SuccessCount() uint32 {
|
||||||
func (s *ServerStatistics) KnownMailservers() []gomatrixserverlib.ServerName {
|
func (s *ServerStatistics) KnownMailservers() []gomatrixserverlib.ServerName {
|
||||||
return s.knownMailservers
|
return s.knownMailservers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ServerStatistics) AddMailservers(mailservers []gomatrixserverlib.ServerName) {
|
||||||
|
seenSet := make(map[gomatrixserverlib.ServerName]bool)
|
||||||
|
uniqueList := []gomatrixserverlib.ServerName{}
|
||||||
|
for _, srv := range mailservers {
|
||||||
|
if seenSet[srv] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seenSet[srv] = true
|
||||||
|
uniqueList = append(uniqueList, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.statistics.DB.AddMailserversForServer(s.serverName, uniqueList)
|
||||||
|
if err == nil {
|
||||||
|
|
||||||
|
for _, newServer := range uniqueList {
|
||||||
|
alreadyKnown := false
|
||||||
|
for _, srv := range s.knownMailservers {
|
||||||
|
if srv == newServer {
|
||||||
|
alreadyKnown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !alreadyKnown {
|
||||||
|
s.knownMailservers = append(s.knownMailservers, newServer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ func TestBackoff(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start by checking that counting successes works.
|
// Start by checking that counting successes works.
|
||||||
server.Success()
|
server.Success(false)
|
||||||
if successes := server.SuccessCount(); successes != 1 {
|
if successes := server.SuccessCount(); successes != 1 {
|
||||||
t.Fatalf("Expected success count 1, got %d", successes)
|
t.Fatalf("Expected success count 1, got %d", successes)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue