Skip to content

fix(payments): stop stale invoices from wedging payment polling - #746

Open
Anshumancanrock wants to merge 2 commits into
cameri:mainfrom
Anshumancanrock:fix/invoice-default-expiry
Open

fix(payments): stop stale invoices from wedging payment polling#746
Anshumancanrock wants to merge 2 commits into
cameri:mainfrom
Anshumancanrock:fix/invoice-default-expiry

Conversation

@Anshumancanrock

@Anshumancanrock Anshumancanrock commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Description

A relay running pay-to-relay can stop admitting paying users, with
delete from invoices as the only known workaround. There are two causes.

The first is invoices that can never be retired. The worker marks a pending
invoice expired when the processor reports it gone and the invoice is past its
expiry. An invoice with no expiry fails that second condition forever. LNURL
creates every invoice without one, so there it hits every unpaid invoice.

The second is the polling window. The worker checks ten pending invoices per run,
always the ten oldest, so once ten are stuck it never looks past them and newer
payments never clear.

Invoices now get a default expiry when the processor supplies none, existing rows
without one are backfilled, and the worker walks the queue ten at a time instead
of restarting at the oldest ten.

Related Issue

#342

Motivation and Context

I did not change when the worker gives up on an invoice. It still retires one only
on a 404, never on a network error. #575 chose that deliberately and it is right:
a network error means we do not know whether the invoice was paid, and LNURL and
NWC have no callback, so retiring one wrongly would lose the payment.

Invoices that used to sit pending forever now get retired
after the default expiry, so on a processor with no callback a very late payment
will not be picked up. Hence a 24 hour default rather than the hour a typical
Lightning invoice lives for, and a documented setting for processors that issue
longer-lived ones.

How Has This Been Tested?

20 new unit tests, and the full suite passes.

Ran the maintenance worker against a local Postgres:

  • Twelve stuck invoices with no expiry. The migration backfilled them, the worker
    drained them over two runs, and newly created invoices were reached on the third.
  • Twelve unexpired invoices that never resolve. Three newer ones went unchecked
    across ten runs before the change, and are picked up every cycle after it.
  • A stale invoice plus a network error still stays pending, so fix: expire stale LNbits pending invoices #575's rule holds.

@changeset-bot

changeset-bot Bot commented Aug 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: edec59d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
nostream Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coveralls

coveralls commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Coverage Status

Coverage is 71.407%Anshumancanrock:fix/invoice-default-expiry into cameri:main. No base build found for cameri:main.

@Anshumancanrock
Anshumancanrock requested a review from cameri August 29, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants