From: Ardis Lu Date: Sat, 25 Jan 2025 08:03:47 +0000 (-0800) Subject: Add example to combine retry and graceful failure strategies X-Git-Tag: v0.1.0~86 X-Git-Url: https://git.ardis.lu/?a=commitdiff_plain;h=27dae854f7393899886553f99d693264b653c8ac;p=csvio Add example to combine retry and graceful failure strategies --- diff --git a/examples/README.md b/examples/README.md index dc9abea..2140aa0 100644 --- a/examples/README.md +++ b/examples/README.md @@ -32,6 +32,8 @@ These examples demonstrate using the `onError` option to handle transformations [Example 2.2: Graceful failure (placeholder value)](./ex2_2.js) +[Example 2.3: Truncated binary exponential backoff (retry with graceful failure)](./ex2_3.js) + ### Section 3: Batch and concurrent processing These examples demonstrate using the `maxBatchSize` and `maxConcurrent` options to process more than one CSV row at a time. diff --git a/examples/data/ex2_3-in.csv b/examples/data/ex2_3-in.csv new file mode 100644 index 0000000..247cafd --- /dev/null +++ b/examples/data/ex2_3-in.csv @@ -0,0 +1,5 @@ +values +a +b +c +d diff --git a/examples/data/ex2_3-out.csv b/examples/data/ex2_3-out.csv new file mode 100644 index 0000000..104d9b8 --- /dev/null +++ b/examples/data/ex2_3-out.csv @@ -0,0 +1,5 @@ +values +a +n/a +c +d diff --git a/examples/ex2_3.js b/examples/ex2_3.js new file mode 100644 index 0000000..25284f2 --- /dev/null +++ b/examples/ex2_3.js @@ -0,0 +1,40 @@ +// ## Example 2.3: Truncated binary exponential backoff (retry with graceful failure) + +import { setTimeout } from 'node:timers/promises'; +import { CSVReader, CSVTransformer, CSVWriter } from '../src/index.js'; + +// Simple implementation of exponential backoff with graceful failure at a given termination point +// https://en.wikipedia.org/wiki/Exponential_backoff +async function backoff(row, fn, truncate = 4) { + for (let n = 0; n < truncate; n++) { + const duration = (2 ** n) * 1000; // 1s, 2s, 4s, 8s, 16s, ... + const jitter = Math.random() * 1000; + + // Reducing sleep by 1000x to avoid slowing down tests, comment out to use real time backoff + const timeout = (duration + jitter) / 1000; + await setTimeout(timeout); + + try { return await fn(row); } + catch { } + } + return row.map(() => 'n/a'); // If tried `truncate` number of times, set row to "n/a" and proceed +} + +// Each row will fail the number of times indicated in the mapping +// All rows should be retried until passed, except for "b" which gracefully fails to "n/a" +const fails = { + a: 1, + b: 8, + c: 4, + d: 0 +}; +function willFail(row) { + if (fails[row[0]]--) { + throw new Error(); + } + return row; +} + +await new CSVReader(new URL('./data/ex2_3-in.csv', import.meta.url)) + .pipeThrough(new CSVTransformer(willFail, { onError: (row, e, fn) => backoff(row, fn, 4) })) + .pipeTo(new CSVWriter(new URL('./data/ex2_3-out.csv', import.meta.url))); \ No newline at end of file