From 89c1b47e9ca73d7bc037f431760674ff919435eb Mon Sep 17 00:00:00 2001 From: Pascal Fischer <32096965+pascal-fischer@users.noreply.github.com> Date: Thu, 15 Oct 2026 16:23:29 +0200 Subject: [PATCH] [management] cancel peer expiration for account if account is gone (#8218) --- management/server/account.go | 21 +++++++++++++++++++-- management/server/account_test.go | 24 ++++++++++++++++++++++++ management/server/peer.go | 6 ++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/management/server/account.go b/management/server/account.go index 90e384ac0..59991a4e4 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -770,7 +770,12 @@ func (am *DefaultAccountManager) peerLoginExpirationJob(ctx context.Context, acc ctx = context.WithValue(ctx, hook.ExecutionContextKey, fmt.Sprintf("%s-PEER-EXPIRATION", hook.SystemSource)) expiredPeers, err := am.getExpiredPeers(ctx, accountID) + if isNotFound(err) { + log.WithContext(ctx).Debugf("account %s not found, stopping peer login expiration job", accountID) + return 0, false + } if err != nil { + log.WithContext(ctx).Errorf("failed getting expired peers for account %s: %v", accountID, err) return peerSchedulerRetryInterval, true } @@ -806,8 +811,12 @@ func (am *DefaultAccountManager) schedulePeerLoginExpiration(ctx context.Context func (am *DefaultAccountManager) peerInactivityExpirationJob(ctx context.Context, accountID string) func() (time.Duration, bool) { return func() (time.Duration, bool) { inactivePeers, err := am.getInactivePeers(ctx, accountID) + if isNotFound(err) { + log.WithContext(ctx).Debugf("account %s not found, stopping peer inactivity expiration job", accountID) + return 0, false + } if err != nil { - log.WithContext(ctx).Errorf("failed getting inactive peers for account %s", accountID) + log.WithContext(ctx).Errorf("failed getting inactive peers for account %s: %v", accountID, err) return peerSchedulerRetryInterval, true } @@ -827,6 +836,14 @@ func (am *DefaultAccountManager) peerInactivityExpirationJob(ctx context.Context } } +func isNotFound(err error) bool { + if err == nil { + return false + } + sErr, ok := status.FromError(err) + return ok && sErr.Type() == status.NotFound +} + // checkAndSchedulePeerInactivityExpiration periodically checks for inactive peers to end their sessions func (am *DefaultAccountManager) checkAndSchedulePeerInactivityExpiration(ctx context.Context, accountID string) { am.peerInactivityExpiry.Cancel(ctx, []string{accountID}) @@ -978,8 +995,8 @@ func (am *DefaultAccountManager) DeleteAccount(ctx context.Context, accountID, u log.WithContext(ctx).Errorf("failed deleting account %s. error: %s", accountID, err) return err } - // cancel peer login expiry job am.peerLoginExpiry.Cancel(ctx, []string{account.Id}) + am.peerInactivityExpiry.Cancel(ctx, []string{account.Id}) am.certChallenges.Forget(account.Id) meta := map[string]any{"account_id": account.Id, "domain": account.Domain, "created_at": account.CreatedAt} diff --git a/management/server/account_test.go b/management/server/account_test.go index 7aa88ee64..ef7525961 100644 --- a/management/server/account_test.go +++ b/management/server/account_test.go @@ -4990,3 +4990,27 @@ func TestUpdateUserAuthWithSingleMode(t *testing.T) { assert.Contains(t, err.Error(), "query failed") }) } + +func TestDefaultAccountManager_ExpirationJobsStopForDeletedAccount(t *testing.T) { + manager, _, err := createManager(t) + require.NoError(t, err, "unable to create account manager") + + ctx := context.Background() + accountID, err := manager.GetAccountIDByUserID(ctx, auth.UserAuth{UserId: userID}) + require.NoError(t, err, "unable to create an account") + + account, err := manager.Store.GetAccount(ctx, accountID) + require.NoError(t, err, "unable to get account") + require.NoError(t, manager.Store.DeleteAccount(ctx, account), "unable to delete account") + + jobs := map[string]func() (time.Duration, bool){ + "login": manager.peerLoginExpirationJob(ctx, accountID), + "inactivity": manager.peerInactivityExpirationJob(ctx, accountID), + } + for name, job := range jobs { + t.Run(name, func(t *testing.T) { + _, reschedule := job() + assert.False(t, reschedule, "job must not reschedule for a deleted account") + }) + } +} diff --git a/management/server/peer.go b/management/server/peer.go index 1e3f72a3c..f21e5ebc9 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -1702,6 +1702,9 @@ func (am *DefaultAccountManager) getNextPeerExpiration(ctx context.Context, acco } settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthNone, accountID) + if isNotFound(err) { + return 0, false + } if err != nil { log.WithContext(ctx).Errorf("failed to get account settings: %v", err) return peerSchedulerRetryInterval, true @@ -1745,6 +1748,9 @@ func (am *DefaultAccountManager) getNextInactivePeerExpiration(ctx context.Conte } settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthNone, accountID) + if isNotFound(err) { + return 0, false + } if err != nil { log.WithContext(ctx).Errorf("failed to get account settings: %v", err) return peerSchedulerRetryInterval, true