Allow retries of pessimistic actions
This commit is contained in:
parent
1f2b717da9
commit
be4ce5daf9
@ -304,14 +304,6 @@ export async function retryPaidAction (actionType, args, incomingContext) {
|
|||||||
throw new Error(`retryPaidAction - must be logged in ${actionType}`)
|
throw new Error(`retryPaidAction - must be logged in ${actionType}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!action.paymentMethods.includes(PAID_ACTION_PAYMENT_METHODS.OPTIMISTIC)) {
|
|
||||||
throw new Error(`retryPaidAction - action does not support optimism ${actionType}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!action.retry) {
|
|
||||||
throw new Error(`retryPaidAction - action does not support retrying ${actionType}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!failedInvoice) {
|
if (!failedInvoice) {
|
||||||
throw new Error(`retryPaidAction - missing invoice ${actionType}`)
|
throw new Error(`retryPaidAction - missing invoice ${actionType}`)
|
||||||
}
|
}
|
||||||
@ -319,7 +311,7 @@ export async function retryPaidAction (actionType, args, incomingContext) {
|
|||||||
const { msatsRequested, actionId, actionArgs } = failedInvoice
|
const { msatsRequested, actionId, actionArgs } = failedInvoice
|
||||||
const retryContext = {
|
const retryContext = {
|
||||||
...incomingContext,
|
...incomingContext,
|
||||||
optimistic: true,
|
optimistic: failedInvoice.actionOptimistic,
|
||||||
me: await models.user.findUnique({ where: { id: me.id } }),
|
me: await models.user.findUnique({ where: { id: me.id } }),
|
||||||
cost: BigInt(msatsRequested),
|
cost: BigInt(msatsRequested),
|
||||||
actionId
|
actionId
|
||||||
@ -345,7 +337,7 @@ export async function retryPaidAction (actionType, args, incomingContext) {
|
|||||||
const invoice = await createDbInvoice(actionType, actionArgs, context)
|
const invoice = await createDbInvoice(actionType, actionArgs, context)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: await action.retry({ invoiceId: failedInvoice.id, newInvoiceId: invoice.id }, context),
|
result: await action.retry?.({ invoiceId: failedInvoice.id, newInvoiceId: invoice.id }, context),
|
||||||
invoice,
|
invoice,
|
||||||
paymentMethod: 'OPTIMISTIC'
|
paymentMethod: 'OPTIMISTIC'
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ export const useQrPayment = () => {
|
|||||||
await invoice.cancel(inv).catch(console.error)
|
await invoice.cancel(inv).catch(console.error)
|
||||||
reject(new InvoiceCanceledError(inv?.hash))
|
reject(new InvoiceCanceledError(inv?.hash))
|
||||||
}
|
}
|
||||||
resolve()
|
resolve(inv)
|
||||||
}
|
}
|
||||||
showModal(onClose =>
|
showModal(onClose =>
|
||||||
<Invoice
|
<Invoice
|
||||||
@ -99,7 +99,7 @@ export const useQrPayment = () => {
|
|||||||
waitFor={waitFor}
|
waitFor={waitFor}
|
||||||
onExpired={inv => reject(new InvoiceExpiredError(inv?.hash))}
|
onExpired={inv => reject(new InvoiceExpiredError(inv?.hash))}
|
||||||
onCanceled={inv => { onClose(); reject(new InvoiceCanceledError(inv?.hash, inv?.actionError)) }}
|
onCanceled={inv => { onClose(); reject(new InvoiceCanceledError(inv?.hash, inv?.actionError)) }}
|
||||||
onPayment={() => { paid = true; onClose(); resolve() }}
|
onPayment={() => { paid = true; onClose(); resolve(inv) }}
|
||||||
poll
|
poll
|
||||||
/>,
|
/>,
|
||||||
{ keepOpen, persistOnNavigate, onClose: cancelAndReject })
|
{ keepOpen, persistOnNavigate, onClose: cancelAndReject })
|
||||||
|
@ -83,7 +83,7 @@ export function usePaidMutation (mutation,
|
|||||||
throw new Error('usePaidMutation: exactly one mutation at a time is supported')
|
throw new Error('usePaidMutation: exactly one mutation at a time is supported')
|
||||||
}
|
}
|
||||||
const response = Object.values(data)[0]
|
const response = Object.values(data)[0]
|
||||||
const invoice = response?.invoice
|
let invoice = response?.invoice
|
||||||
|
|
||||||
// if the mutation returns an invoice, pay it
|
// if the mutation returns an invoice, pay it
|
||||||
if (invoice) {
|
if (invoice) {
|
||||||
@ -113,7 +113,8 @@ export function usePaidMutation (mutation,
|
|||||||
// the action is pessimistic
|
// the action is pessimistic
|
||||||
try {
|
try {
|
||||||
// wait for the invoice to be paid
|
// wait for the invoice to be paid
|
||||||
await waitForPayment(invoice, { alwaysShowQROnFailure: true, persistOnNavigate, waitFor })
|
// returns the invoice that was paid since it might have been updated via retries
|
||||||
|
invoice = await waitForPayment(invoice, { alwaysShowQROnFailure: true, persistOnNavigate, waitFor })
|
||||||
if (!response.result) {
|
if (!response.result) {
|
||||||
// if the mutation didn't return any data, ie pessimistic, we need to fetch it
|
// if the mutation didn't return any data, ie pessimistic, we need to fetch it
|
||||||
const { data: { paidAction } } = await getPaidAction({ variables: { invoiceId: parseInt(invoice.id) } })
|
const { data: { paidAction } } = await getPaidAction({ variables: { invoiceId: parseInt(invoice.id) } })
|
||||||
|
@ -47,7 +47,7 @@ export function useWalletPayment () {
|
|||||||
let walletInvoice = invoice
|
let walletInvoice = invoice
|
||||||
|
|
||||||
for (const wallet of walletsWithPayments) {
|
for (const wallet of walletsWithPayments) {
|
||||||
const controller = invoiceController(walletInvoice.id, invoiceHelper.isInvoice)
|
const controller = invoiceController(walletInvoice, invoiceHelper.isInvoice)
|
||||||
try {
|
try {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
// can't await wallet payments since we might pay hold invoices and thus payments might not settle immediately.
|
// can't await wallet payments since we might pay hold invoices and thus payments might not settle immediately.
|
||||||
@ -102,20 +102,20 @@ export function useWalletPayment () {
|
|||||||
return waitForPayment
|
return waitForPayment
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceController = (id, isInvoice) => {
|
const invoiceController = (inv, isInvoice) => {
|
||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
const signal = controller.signal
|
const signal = controller.signal
|
||||||
controller.wait = async (waitFor = inv => inv?.actionState === 'PAID') => {
|
controller.wait = async (waitFor = inv => inv?.actionState === 'PAID') => {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
const interval = setInterval(async () => {
|
const interval = setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
const paid = await isInvoice({ id }, waitFor)
|
const paid = await isInvoice(inv, waitFor)
|
||||||
if (paid) {
|
if (paid) {
|
||||||
resolve()
|
resolve(inv)
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
signal.removeEventListener('abort', abort)
|
signal.removeEventListener('abort', abort)
|
||||||
} else {
|
} else {
|
||||||
console.info(`invoice #${id}: waiting for payment ...`)
|
console.info(`invoice #${inv.id}: waiting for payment ...`)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(err)
|
reject(err)
|
||||||
@ -125,8 +125,8 @@ const invoiceController = (id, isInvoice) => {
|
|||||||
}, FAST_POLL_INTERVAL)
|
}, FAST_POLL_INTERVAL)
|
||||||
|
|
||||||
const abort = () => {
|
const abort = () => {
|
||||||
console.info(`invoice #${id}: stopped waiting`)
|
console.info(`invoice #${inv.id}: stopped waiting`)
|
||||||
resolve()
|
resolve(inv)
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
signal.removeEventListener('abort', abort)
|
signal.removeEventListener('abort', abort)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user