wallet-cli: add --expect-success flag, exit with error on max retries

This commit is contained in:
Florian Dold 2022-09-21 19:53:38 +02:00
parent 4fdc009753
commit 26cf19ab6c
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
2 changed files with 34 additions and 4 deletions

View File

@ -81,6 +81,10 @@ export {
const logger = new Logger("taler-wallet-cli.ts"); 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) => { process.on("unhandledRejection", (error: any) => {
logger.error("unhandledRejection", error.message); logger.error("unhandledRejection", error.message);
logger.error("stack", error.stack); logger.error("stack", error.stack);
@ -272,6 +276,9 @@ walletCli
.subcommand("api", "api", { help: "Call the wallet-core API directly." }) .subcommand("api", "api", { help: "Call the wallet-core API directly." })
.requiredArgument("operation", clk.STRING) .requiredArgument("operation", clk.STRING)
.requiredArgument("request", 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) => { .action(async (args) => {
await withWallet(args, async (wallet) => { await withWallet(args, async (wallet) => {
let requestJson; let requestJson;
@ -289,8 +296,14 @@ walletCli
requestJson, requestJson,
); );
console.log(JSON.stringify(resp, undefined, 2)); console.log(JSON.stringify(resp, undefined, 2));
if (resp.type === "error") {
if (args.api.expectSuccess) {
process.exit(EXIT_API_ERROR);
}
}
} catch (e) { } catch (e) {
logger.error(`Got exception while handling API request ${e}`); logger.error(`Got exception while handling API request ${e}`);
process.exit(EXIT_EXCEPTION);
} }
}); });
logger.info("finished handling API request"); logger.info("finished handling API request");
@ -357,11 +370,14 @@ walletCli
.action(async (args) => { .action(async (args) => {
await withWallet(args, async (wallet) => { await withWallet(args, async (wallet) => {
logger.info("running until pending operations are finished"); logger.info("running until pending operations are finished");
await wallet.ws.runTaskLoop({ const resp = await wallet.ws.runTaskLoop({
maxRetries: args.finishPendingOpt.maxRetries, maxRetries: args.finishPendingOpt.maxRetries,
stopWhenDone: true, stopWhenDone: true,
}); });
wallet.ws.stop(); wallet.ws.stop();
if (resp.retriesExceeded) {
process.exit(EXIT_RETRIES_EXCEEDED);
}
}); });
}); });

View File

@ -477,6 +477,13 @@ export interface RetryLoopOpts {
stopWhenDone?: boolean; stopWhenDone?: boolean;
} }
export interface TaskLoopResult {
/**
* Was the maximum number of retries exceeded in a task?
*/
retriesExceeded: boolean;
}
/** /**
* Main retry loop of the wallet. * Main retry loop of the wallet.
* *
@ -485,7 +492,8 @@ export interface RetryLoopOpts {
async function runTaskLoop( async function runTaskLoop(
ws: InternalWalletState, ws: InternalWalletState,
opts: RetryLoopOpts = {}, opts: RetryLoopOpts = {},
): Promise<void> { ): Promise<TaskLoopResult> {
let retriesExceeded = false;
for (let iteration = 0; !ws.stopped; iteration++) { for (let iteration = 0; !ws.stopped; iteration++) {
const pending = await getPendingOperations(ws); const pending = await getPendingOperations(ws);
logger.trace(`pending operations: ${j2s(pending)}`); logger.trace(`pending operations: ${j2s(pending)}`);
@ -497,6 +505,7 @@ async function runTaskLoop(
const maxRetries = opts.maxRetries; const maxRetries = opts.maxRetries;
if (maxRetries && p.retryInfo && p.retryInfo.retryCounter > maxRetries) { if (maxRetries && p.retryInfo && p.retryInfo.retryCounter > maxRetries) {
retriesExceeded = true;
logger.warn( logger.warn(
`skipping, as ${maxRetries} retries are exceeded in an operation of type ${p.type}`, `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) { if (opts.stopWhenDone && numGivingLiveness === 0 && iteration !== 0) {
logger.warn(`stopping, as no pending operations have lifeness`); 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 // 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"); logger.trace("exiting wallet retry loop");
return {
retriesExceeded,
};
} }
/** /**
@ -1526,7 +1540,7 @@ export class Wallet {
return runPending(this.ws, forceNow); return runPending(this.ws, forceNow);
} }
runTaskLoop(opts?: RetryLoopOpts): Promise<void> { runTaskLoop(opts?: RetryLoopOpts): Promise<TaskLoopResult> {
return runTaskLoop(this.ws, opts); return runTaskLoop(this.ws, opts);
} }