aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/util/retries.ts
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-09-05 18:12:30 +0200
committerFlorian Dold <florian@dold.me>2022-09-13 16:10:41 +0200
commit13e7a674778754c0ed641dfd428e3d6b2b71ab2d (patch)
treef2a0e5029305a9b818416fd94908ef77cdd7446f /packages/taler-wallet-core/src/util/retries.ts
parentf9f2911c761af1c8ed1c323dcd414cbaa9eeae7c (diff)
downloadwallet-core-13e7a674778754c0ed641dfd428e3d6b2b71ab2d.tar.xz
wallet-core: uniform retry handling
Diffstat (limited to 'packages/taler-wallet-core/src/util/retries.ts')
-rw-r--r--packages/taler-wallet-core/src/util/retries.ts116
1 files changed, 115 insertions, 1 deletions
diff --git a/packages/taler-wallet-core/src/util/retries.ts b/packages/taler-wallet-core/src/util/retries.ts
index 13a05b385..3a41e8348 100644
--- a/packages/taler-wallet-core/src/util/retries.ts
+++ b/packages/taler-wallet-core/src/util/retries.ts
@@ -21,7 +21,29 @@
/**
* Imports.
*/
-import { AbsoluteTime, Duration } from "@gnu-taler/taler-util";
+import {
+ AbsoluteTime,
+ Duration,
+ TalerErrorDetail,
+} from "@gnu-taler/taler-util";
+import {
+ BackupProviderRecord,
+ DepositGroupRecord,
+ ExchangeRecord,
+ OperationAttemptResult,
+ OperationAttemptResultType,
+ ProposalRecord,
+ PurchaseRecord,
+ RecoupGroupRecord,
+ RefreshGroupRecord,
+ TipRecord,
+ WalletStoresV1,
+ WithdrawalGroupRecord,
+} from "../db.js";
+import { TalerError } from "../errors.js";
+import { InternalWalletState } from "../internal-wallet-state.js";
+import { PendingTaskType } from "../pending-types.js";
+import { GetReadWriteAccess } from "./query.js";
export interface RetryInfo {
firstTry: AbsoluteTime;
@@ -108,3 +130,95 @@ export namespace RetryInfo {
return r2;
}
}
+
+export namespace RetryTags {
+ export function forWithdrawal(wg: WithdrawalGroupRecord): string {
+ return `${PendingTaskType.Withdraw}:${wg.withdrawalGroupId}`;
+ }
+ export function forExchangeUpdate(exch: ExchangeRecord): string {
+ return `${PendingTaskType.ExchangeUpdate}:${exch.baseUrl}`;
+ }
+ export function forExchangeCheckRefresh(exch: ExchangeRecord): string {
+ return `${PendingTaskType.ExchangeCheckRefresh}:${exch.baseUrl}`;
+ }
+ export function forProposalClaim(pr: ProposalRecord): string {
+ return `${PendingTaskType.ProposalDownload}:${pr.proposalId}`;
+ }
+ export function forTipPickup(tipRecord: TipRecord): string {
+ return `${PendingTaskType.TipPickup}:${tipRecord.walletTipId}`;
+ }
+ export function forRefresh(refreshGroupRecord: RefreshGroupRecord): string {
+ return `${PendingTaskType.TipPickup}:${refreshGroupRecord.refreshGroupId}`;
+ }
+ export function forPay(purchaseRecord: PurchaseRecord): string {
+ return `${PendingTaskType.Pay}:${purchaseRecord.proposalId}`;
+ }
+ export function forRefundQuery(purchaseRecord: PurchaseRecord): string {
+ return `${PendingTaskType.RefundQuery}:${purchaseRecord.proposalId}`;
+ }
+ export function forRecoup(recoupRecord: RecoupGroupRecord): string {
+ return `${PendingTaskType.Recoup}:${recoupRecord.recoupGroupId}`;
+ }
+ export function forDeposit(depositRecord: DepositGroupRecord): string {
+ return `${PendingTaskType.Deposit}:${depositRecord.depositGroupId}`;
+ }
+ export function forBackup(backupRecord: BackupProviderRecord): string {
+ return `${PendingTaskType.Backup}:${backupRecord.baseUrl}`;
+ }
+}
+
+export async function scheduleRetryInTx(
+ ws: InternalWalletState,
+ tx: GetReadWriteAccess<{
+ operationRetries: typeof WalletStoresV1.operationRetries;
+ }>,
+ opId: string,
+ errorDetail?: TalerErrorDetail,
+): Promise<void> {
+ let retryRecord = await tx.operationRetries.get(opId);
+ if (!retryRecord) {
+ retryRecord = {
+ id: opId,
+ retryInfo: RetryInfo.reset(),
+ };
+ if (errorDetail) {
+ retryRecord.lastError = errorDetail;
+ }
+ } else {
+ retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo);
+ if (errorDetail) {
+ retryRecord.lastError = errorDetail;
+ } else {
+ delete retryRecord.lastError;
+ }
+ }
+ await tx.operationRetries.put(retryRecord);
+}
+
+export async function scheduleRetry(
+ ws: InternalWalletState,
+ opId: string,
+ errorDetail?: TalerErrorDetail,
+): Promise<void> {
+ return await ws.db
+ .mktx((x) => ({ operationRetries: x.operationRetries }))
+ .runReadWrite(async (tx) => {
+ scheduleRetryInTx(ws, tx, opId, errorDetail);
+ });
+}
+
+/**
+ * Run an operation handler, expect a success result and extract the success value.
+ */
+export async function runOperationHandlerForResult<T>(
+ res: OperationAttemptResult<T>,
+): Promise<T> {
+ switch (res.type) {
+ case OperationAttemptResultType.Finished:
+ return res.result;
+ case OperationAttemptResultType.Error:
+ throw TalerError.fromUncheckedDetail(res.errorDetail);
+ default:
+ throw Error(`unexpected operation result (${res.type})`);
+ }
+}