From 26cf19ab6c896a299a12605a7b1723540763f52c Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 21 Sep 2022 19:53:38 +0200 Subject: [PATCH] wallet-cli: add --expect-success flag, exit with error on max retries --- packages/taler-wallet-cli/src/index.ts | 18 +++++++++++++++++- packages/taler-wallet-core/src/wallet.ts | 20 +++++++++++++++++--- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index 8fd0de642..5aa7c49f1 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -81,6 +81,10 @@ export { const logger = new Logger("taler-wallet-cli.ts"); +const EXIT_EXCEPTION = 4; +const EXIT_API_ERROR = 5; +const EXIT_RETRIES_EXCEEDED = 6; + process.on("unhandledRejection", (error: any) => { logger.error("unhandledRejection", error.message); logger.error("stack", error.stack); @@ -272,6 +276,9 @@ walletCli .subcommand("api", "api", { help: "Call the wallet-core API directly." }) .requiredArgument("operation", clk.STRING) .requiredArgument("request", clk.STRING) + .flag("expectSuccess", ["--expect-success"], { + help: "Exit with non-zero status code when request fails instead of returning error JSON.", + }) .action(async (args) => { await withWallet(args, async (wallet) => { let requestJson; @@ -289,8 +296,14 @@ walletCli requestJson, ); console.log(JSON.stringify(resp, undefined, 2)); + if (resp.type === "error") { + if (args.api.expectSuccess) { + process.exit(EXIT_API_ERROR); + } + } } catch (e) { logger.error(`Got exception while handling API request ${e}`); + process.exit(EXIT_EXCEPTION); } }); logger.info("finished handling API request"); @@ -357,11 +370,14 @@ walletCli .action(async (args) => { await withWallet(args, async (wallet) => { logger.info("running until pending operations are finished"); - await wallet.ws.runTaskLoop({ + const resp = await wallet.ws.runTaskLoop({ maxRetries: args.finishPendingOpt.maxRetries, stopWhenDone: true, }); wallet.ws.stop(); + if (resp.retriesExceeded) { + process.exit(EXIT_RETRIES_EXCEEDED); + } }); }); diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index c91a96841..3ee37ec1a 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -477,6 +477,13 @@ export interface RetryLoopOpts { stopWhenDone?: boolean; } +export interface TaskLoopResult { + /** + * Was the maximum number of retries exceeded in a task? + */ + retriesExceeded: boolean; +} + /** * Main retry loop of the wallet. * @@ -485,7 +492,8 @@ export interface RetryLoopOpts { async function runTaskLoop( ws: InternalWalletState, opts: RetryLoopOpts = {}, -): Promise { +): Promise { + let retriesExceeded = false; for (let iteration = 0; !ws.stopped; iteration++) { const pending = await getPendingOperations(ws); logger.trace(`pending operations: ${j2s(pending)}`); @@ -497,6 +505,7 @@ async function runTaskLoop( const maxRetries = opts.maxRetries; if (maxRetries && p.retryInfo && p.retryInfo.retryCounter > maxRetries) { + retriesExceeded = true; logger.warn( `skipping, as ${maxRetries} retries are exceeded in an operation of type ${p.type}`, ); @@ -514,7 +523,9 @@ async function runTaskLoop( if (opts.stopWhenDone && numGivingLiveness === 0 && iteration !== 0) { logger.warn(`stopping, as no pending operations have lifeness`); - return; + return { + retriesExceeded, + }; } // Make sure that we run tasks that don't give lifeness at least @@ -557,6 +568,9 @@ async function runTaskLoop( } } logger.trace("exiting wallet retry loop"); + return { + retriesExceeded, + }; } /** @@ -1526,7 +1540,7 @@ export class Wallet { return runPending(this.ws, forceNow); } - runTaskLoop(opts?: RetryLoopOpts): Promise { + runTaskLoop(opts?: RetryLoopOpts): Promise { return runTaskLoop(this.ws, opts); }