fix: stop retrying NIP47 info publish for deleted apps (#2391)

The NIP47 info publish queue re-enqueued every failed publish with an
incrementing backoff and no terminal condition. When an app connection
was deleted, PublishNip47Info fails the `db.First(&app, appId)` lookup
with gorm.ErrRecordNotFound on every attempt, so the item was retried
forever (observed as a steady stream of "Failed to publish NIP47 info
from queue" errors from affected instances).

Drop the queue item when the app no longer exists instead of requeuing.
All other errors (offline relay, timeouts) still retry with backoff.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Bumann 2026-06-04 08:29:05 +02:00 committed by GitHub
parent 84e56a23db
commit bc49cb7d33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 49 additions and 0 deletions

View file

@ -2,6 +2,7 @@ package nip47
import (
"context"
"errors"
"time"
"github.com/getAlby/go-nostr"
@ -114,6 +115,18 @@ func (svc *nip47Service) StartNip47InfoPublisher(ctx context.Context, pool *nost
case req := <-svc.nip47InfoPublishQueue.Channel():
_, err := svc.PublishNip47Info(ctx, pool, req.AppId, req.AppWalletPubKey, req.AppWalletPrivKey, req.RelayUrl, lnClient)
if err != nil {
// the app connection no longer exists (e.g. it was deleted),
// so the info event can never be published - drop the item
// instead of retrying forever
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Logger.WithError(err).WithFields(logrus.Fields{
"app_id": req.AppId,
"wallet_pubkey": req.AppWalletPubKey,
"relay_url": req.RelayUrl,
}).Warn("Skipping NIP47 info publish for deleted app")
continue
}
logger.Logger.WithError(err).WithFields(logrus.Fields{
"wallet_pubkey": req.AppWalletPubKey,
"relay_url": req.RelayUrl,

View file

@ -0,0 +1,36 @@
package nip47
import (
"context"
"testing"
"github.com/getAlby/go-nostr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"github.com/getAlby/hub/alby"
"github.com/getAlby/hub/tests"
)
// When an app connection has been deleted, publishing its NIP47 info must
// surface gorm.ErrRecordNotFound so the publish queue can drop the item
// instead of retrying forever.
func TestPublishNip47Info_AppNotFound(t *testing.T) {
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
albyOAuthSvc := alby.NewAlbyOAuthService(svc.DB, svc.Cfg, svc.Keys, svc.EventPublisher)
nip47svc := NewNip47Service(svc.DB, svc.Cfg, svc.Keys, svc.EventPublisher, albyOAuthSvc)
walletPrivKey := nostr.GeneratePrivateKey()
walletPubKey, err := nostr.GetPublicKey(walletPrivKey)
require.NoError(t, err)
// app id 9999999 does not exist; the DB lookup fails before the relay pool
// is ever used, so a nil pool/lnClient is fine here.
_, err = nip47svc.PublishNip47Info(context.Background(), nil, 9999999, walletPubKey, walletPrivKey, "wss://relay.example.com", nil)
require.Error(t, err)
assert.ErrorIs(t, err, gorm.ErrRecordNotFound)
}