@baukit/sync-client 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -74,11 +74,50 @@ The environment reports foreground state and connectivity. The scheduler runs on
74
74
  app returns to the foreground, when connectivity returns, and on the interval. It installs no
75
75
  interval while backgrounded and ignores connectivity events there.
76
76
 
77
- A failing run reaches `onError` and does not stop scheduling. Backoff between attempts belongs to
78
- the product's engine, inside `run()`, where it can see which failures are retryable.
77
+ A failing run reaches `onError` and does not stop scheduling. Without `retry`, the next attempt
78
+ waits for the next trigger.
79
79
 
80
- If the engine waits inside its own retry delay, pass `onRecoverySignal` to the scheduler and wake
81
- that delay there. The scheduler calls it with `active` before a foreground-triggered run and with
80
+ ### Retry and backoff
81
+
82
+ Pass `retry` to retry a failed run after a delay. The product decides which failures are worth a
83
+ retry and how long to wait, because only it knows its error types; the scheduler owns the attempt
84
+ count, the wait, and waking it early. `fullJitterBackoffMs` from `@baukit/api-runtime/backoff` is
85
+ the Baukit delay policy. The root entry of this package still imports nothing, so the product
86
+ passes the policy in:
87
+
88
+ ```ts
89
+ import { fullJitterBackoffMs } from '@baukit/api-runtime/backoff';
90
+ import { SyncRateLimitError, SyncScheduler, SyncTransportError } from '@baukit/sync-client';
91
+
92
+ const scheduler = new SyncScheduler(() => engine.syncOnce(), environment, {
93
+ retry: {
94
+ maxRetries: 4,
95
+ delayMs: (error, retryIndex) => {
96
+ if (error instanceof SyncRateLimitError) return Math.max(0, Date.parse(error.retryAt) - Date.now());
97
+ if (error instanceof SyncTransportError && !error.retryable) return null;
98
+ return fullJitterBackoffMs(retryIndex, { baseDelayMs: 500, maxDelayMs: 30_000 });
99
+ },
100
+ onRetryScheduled: ({ delayMs }) => status.showRetryAt(Date.now() + delayMs),
101
+ },
102
+ });
103
+ ```
104
+
105
+ After a failed run the scheduler asks `delayMs(error, retryIndex)`. `null` means no retry. A number
106
+ is the wait in milliseconds, and `onRetryScheduled` hears about it before the wait starts. The
107
+ retry index counts from 0 and restarts after a success. After `maxRetries` retries the scheduler
108
+ waits for the next trigger. A delay that is negative or not finite, or a `delayMs` that throws,
109
+ reaches `onError` and ends the retries. A `maxRetries` that is not a non-negative integer throws a
110
+ `RangeError` from the constructor.
111
+
112
+ The wait is a one-shot timer built from the environment's `setInterval`, so no environment
113
+ changes. Any trigger during the wait ends it at once and restarts the retry index at 0: a manual
114
+ `trigger()`, the interval, returning to the foreground, or connectivity returning while in the
115
+ foreground. A follow-up request during the wait does not end it, because the retry will send the
116
+ same writes. `stop()` ends the wait without another run, and a wait that ends while the app is
117
+ backgrounded runs nothing until the app returns.
118
+
119
+ If the engine waits inside its own retry delay instead, pass `onRecoverySignal` to the scheduler
120
+ and wake that delay there. The scheduler calls it with `active` before a foreground-triggered run and with
82
121
  `online` before an online-triggered run. Online recovery is reported even while the scheduler is
83
122
  backgrounded, although the scheduler still waits for foreground before starting another run.
84
123
  Retry wake-up belongs in this scheduler option, not in a decorated environment, because the
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export type { HlcPhysicalClock, HlcStorage, HybridLogicalClockErrorCode, HybridL
5
5
  export { dependencyRankByOrder, rankPushBatch, validatePushOutcomeCoverage } from './push-batch.js';
6
6
  export type { PushCandidate, PushOutcomeCoverageOptions, RankedPushItem, RankPushBatchOptions, } from './push-batch.js';
7
7
  export { SyncScheduler } from './scheduler.js';
8
- export type { SyncSchedulerEnvironment, SyncSchedulerOptions, SyncSchedulerRecoverySignal, SyncSchedulerTimer, } from './scheduler.js';
8
+ export type { SyncSchedulerEnvironment, SyncSchedulerOptions, SyncSchedulerRecoverySignal, SyncSchedulerRetry, SyncSchedulerRetryOptions, SyncSchedulerTimer, } from './scheduler.js';
9
9
  export { deriveInitialSyncState, deriveLocalStoreReadiness, SyncStatusStore } from './store.js';
10
10
  export type { InitialPullStatus, InitialSyncState, LocalStoreReadiness, LocalStoreReadinessInput, SyncAttentionItem, SyncFailureUpdate, SyncStatus, SyncStatusHydration, SyncStatusSink, SyncStatusSnapshot, SyncStatusStoreOptions, } from './store.js';
11
11
  export { commitCursorAfterLocalTransaction, DEFAULT_RETRY_AFTER_FALLBACK_MS, parseRetryAfter, SyncTransport, validatePullPage, } from './transport.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,0BAA0B,EAC1B,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,4BAA4B,EAC5B,kBAAkB,EAClB,uBAAuB,EACvB,4BAA4B,EAC5B,eAAe,EACf,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,gBAAgB,EAChB,UAAU,EACV,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AACpG,YAAY,EACV,aAAa,EACb,0BAA0B,EAC1B,cAAc,EACd,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EACV,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,EAC3B,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChG,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iCAAiC,EACjC,+BAA+B,EAC/B,eAAe,EACf,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,mCAAmC,EACnC,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,0BAA0B,EAC1B,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,4BAA4B,EAC5B,kBAAkB,EAClB,uBAAuB,EACvB,4BAA4B,EAC5B,eAAe,EACf,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,gBAAgB,EAChB,UAAU,EACV,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AACpG,YAAY,EACV,aAAa,EACb,0BAA0B,EAC1B,cAAc,EACd,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EACV,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,EAC3B,kBAAkB,EAClB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChG,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iCAAiC,EACjC,+BAA+B,EAC/B,eAAe,EACf,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,mCAAmC,EACnC,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,0BAA0B,EAC1B,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,4BAA4B,EAC5B,kBAAkB,EAClB,uBAAuB,EACvB,4BAA4B,EAC5B,eAAe,EACf,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAOlB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAOpG,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAO/C,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAchG,OAAO,EACL,iCAAiC,EACjC,+BAA+B,EAC/B,eAAe,EACf,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,0BAA0B,EAC1B,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,4BAA4B,EAC5B,kBAAkB,EAClB,uBAAuB,EACvB,4BAA4B,EAC5B,eAAe,EACf,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAOlB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAOpG,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAS/C,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAchG,OAAO,EACL,iCAAiC,EACjC,+BAA+B,EAC/B,eAAe,EACf,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC"}
@@ -16,10 +16,30 @@ export interface SyncSchedulerEnvironment {
16
16
  export type SyncSchedulerTimer = {
17
17
  readonly __syncSchedulerTimer?: never;
18
18
  } & object;
19
+ /** A retry the scheduler is about to wait for. */
20
+ export interface SyncSchedulerRetry {
21
+ readonly error: unknown;
22
+ /** Counts retries since the last success or wake-up, from 0. */
23
+ readonly retryIndex: number;
24
+ readonly delayMs: number;
25
+ }
26
+ /** Retries a failed run after a delay the product chooses. */
27
+ export interface SyncSchedulerRetryOptions {
28
+ /** Retries after a failed run before the scheduler waits for the next trigger. */
29
+ readonly maxRetries: number;
30
+ /**
31
+ * The delay before retry `retryIndex`, or `null` when the failure must not be retried.
32
+ * `fullJitterBackoffMs` from `@baukit/api-runtime/backoff` gives bounded, jittered delays.
33
+ */
34
+ readonly delayMs: (error: unknown, retryIndex: number) => number | null;
35
+ /** Runs before each wait, for example to show when the next attempt starts. */
36
+ readonly onRetryScheduled?: (retry: SyncSchedulerRetry) => void;
37
+ }
19
38
  export interface SyncSchedulerOptions {
20
39
  intervalMs?: number;
21
40
  onError?: (error: unknown) => void;
22
41
  onRecoverySignal?: (signal: SyncSchedulerRecoverySignal) => void;
42
+ retry?: SyncSchedulerRetryOptions;
23
43
  }
24
44
  export type SyncSchedulerRecoverySignal = 'active' | 'online';
25
45
  /**
@@ -27,7 +47,9 @@ export type SyncSchedulerRecoverySignal = 'active' | 'online';
27
47
  *
28
48
  * A trigger that arrives while a run is active joins that run. A follow-up
29
49
  * requested during a run replays the callback once after it settles, so writes
30
- * made mid-run are never left unsent without starting a parallel run.
50
+ * made mid-run are never left unsent without starting a parallel run. With
51
+ * `retry`, a failed run is retried after the chosen delay; a trigger during
52
+ * that delay ends it and restarts the retry count.
31
53
  */
32
54
  export declare class SyncScheduler {
33
55
  private readonly run;
@@ -35,20 +57,29 @@ export declare class SyncScheduler {
35
57
  private readonly intervalMs;
36
58
  private readonly onError;
37
59
  private readonly onRecoverySignal;
60
+ private readonly retry;
38
61
  private active;
39
62
  private started;
40
63
  private inFlight;
41
64
  private rerunRequested;
42
65
  private interval;
43
66
  private subscriptions;
67
+ private wakeRetry;
68
+ private stops;
44
69
  constructor(run: () => Promise<unknown>, environment: SyncSchedulerEnvironment, options?: SyncSchedulerOptions);
45
70
  start(): void;
46
71
  stop(): void;
47
- /** Starts a run, or joins the active one. */
72
+ /** Starts a run, or joins the active one and ends its retry delay. */
48
73
  trigger(): Promise<void>;
49
74
  /** Queues exactly one more run when a run is already active. */
50
75
  requestFollowUp(): Promise<void>;
51
76
  private runUntilSettled;
77
+ /** Read through a method: a follow-up can arrive while `run` is awaited. */
78
+ private followUpRequested;
79
+ private runOnce;
80
+ private retryDelay;
81
+ /** The environment has interval timers only, so the delay clears its interval on the first tick. */
82
+ private waitForRetry;
52
83
  private refreshInterval;
53
84
  private stopInterval;
54
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,IAAI,OAAO,CAAC;IACpB,eAAe,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACjE,eAAe,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAClD,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,YAAY,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAC5E,aAAa,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACjD;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG,MAAM,CAAC;AAEpF,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAClE;AAED,MAAM,MAAM,2BAA2B,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAQ9D;;;;;;GAMG;AACH,qBAAa,aAAa;IAYtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAZ9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IACnD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgD;IACjF,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,aAAa,CAAsB;gBAGxB,GAAG,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC3B,WAAW,EAAE,wBAAwB,EACtD,OAAO,GAAE,oBAAyB;IAOpC,KAAK,IAAI,IAAI;IA4Bb,IAAI,IAAI,IAAI;IAUZ,6CAA6C;IAC7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAexB,gEAAgE;IAChE,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;YAQlB,eAAe;IAa7B,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,YAAY;CAOrB"}
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,IAAI,OAAO,CAAC;IACpB,eAAe,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACjE,eAAe,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAClD,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,YAAY,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAC5E,aAAa,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACjD;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG,MAAM,CAAC;AAEpF,kDAAkD;AAClD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,8DAA8D;AAC9D,MAAM,WAAW,yBAAyB;IACxC,kFAAkF;IAClF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACxE,+EAA+E;IAC/E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACjE;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,IAAI,CAAC;IACjE,KAAK,CAAC,EAAE,yBAAyB,CAAC;CACnC;AAED,MAAM,MAAM,2BAA2B,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAmB9D;;;;;;;;GAQG;AACH,qBAAa,aAAa;IAetB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAf9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IACnD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgD;IACjF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAC9D,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,KAAK,CAAK;gBAGC,GAAG,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC3B,WAAW,EAAE,wBAAwB,EACtD,OAAO,GAAE,oBAAyB;IASpC,KAAK,IAAI,IAAI;IA4Bb,IAAI,IAAI,IAAI;IAYZ,sEAAsE;IACtE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBxB,gEAAgE;IAChE,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;YAQlB,eAAe;IA0B7B,4EAA4E;IAC5E,OAAO,CAAC,iBAAiB;YAIX,OAAO;IAUrB,OAAO,CAAC,UAAU;IAkBlB,oGAAoG;IACpG,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,YAAY;CAOrB"}
package/dist/scheduler.js CHANGED
@@ -2,12 +2,22 @@ const DEFAULT_INTERVAL_MS = 5 * 60 * 1000;
2
2
  function noop() {
3
3
  return;
4
4
  }
5
+ function validateRetry(retry) {
6
+ if (retry === undefined) {
7
+ return;
8
+ }
9
+ if (!Number.isInteger(retry.maxRetries) || retry.maxRetries < 0) {
10
+ throw new RangeError('retry.maxRetries must be a non-negative integer');
11
+ }
12
+ }
5
13
  /**
6
14
  * Runs one opaque sync callback at most once at a time.
7
15
  *
8
16
  * A trigger that arrives while a run is active joins that run. A follow-up
9
17
  * requested during a run replays the callback once after it settles, so writes
10
- * made mid-run are never left unsent without starting a parallel run.
18
+ * made mid-run are never left unsent without starting a parallel run. With
19
+ * `retry`, a failed run is retried after the chosen delay; a trigger during
20
+ * that delay ends it and restarts the retry count.
11
21
  */
12
22
  export class SyncScheduler {
13
23
  run;
@@ -15,18 +25,23 @@ export class SyncScheduler {
15
25
  intervalMs;
16
26
  onError;
17
27
  onRecoverySignal;
28
+ retry;
18
29
  active = false;
19
30
  started = false;
20
31
  inFlight = null;
21
32
  rerunRequested = false;
22
33
  interval = null;
23
34
  subscriptions = [];
35
+ wakeRetry = null;
36
+ stops = 0;
24
37
  constructor(run, environment, options = {}) {
25
38
  this.run = run;
26
39
  this.environment = environment;
40
+ validateRetry(options.retry);
27
41
  this.intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
28
42
  this.onError = options.onError ?? noop;
29
43
  this.onRecoverySignal = options.onRecoverySignal ?? noop;
44
+ this.retry = options.retry;
30
45
  }
31
46
  start() {
32
47
  if (this.started) {
@@ -57,16 +72,19 @@ export class SyncScheduler {
57
72
  }
58
73
  stop() {
59
74
  this.started = false;
75
+ this.stops += 1;
60
76
  this.rerunRequested = false;
77
+ this.wakeRetry?.('stopped');
61
78
  this.stopInterval();
62
79
  this.subscriptions.forEach((unsubscribe) => {
63
80
  unsubscribe();
64
81
  });
65
82
  this.subscriptions = [];
66
83
  }
67
- /** Starts a run, or joins the active one. */
84
+ /** Starts a run, or joins the active one and ends its retry delay. */
68
85
  trigger() {
69
86
  if (this.inFlight) {
87
+ this.wakeRetry?.('triggered');
70
88
  return this.inFlight;
71
89
  }
72
90
  const task = Promise.resolve()
@@ -88,18 +106,80 @@ export class SyncScheduler {
88
106
  return this.trigger();
89
107
  }
90
108
  async runUntilSettled() {
91
- let rerun = true;
92
- while (rerun) {
109
+ const stopsAtStart = this.stops;
110
+ let retryIndex = 0;
111
+ for (;;) {
93
112
  this.rerunRequested = false;
94
- try {
95
- await this.run();
113
+ const failure = await this.runOnce();
114
+ if (failure === null) {
115
+ retryIndex = 0;
116
+ if (!this.followUpRequested())
117
+ return;
118
+ continue;
119
+ }
120
+ const delayMs = this.retryDelay(failure.error, retryIndex);
121
+ if (delayMs === null) {
122
+ if (!this.followUpRequested())
123
+ return;
124
+ continue;
96
125
  }
97
- catch (error) {
98
- this.onError(error);
126
+ this.retry?.onRetryScheduled?.({ error: failure.error, retryIndex, delayMs });
127
+ const wake = await this.waitForRetry(delayMs);
128
+ const stopped = this.stops !== stopsAtStart;
129
+ if (stopped || (wake === 'elapsed' && this.started && !this.active)) {
130
+ return;
99
131
  }
100
- rerun = this.rerunRequested;
132
+ retryIndex = wake === 'triggered' ? 0 : retryIndex + 1;
133
+ }
134
+ }
135
+ /** Read through a method: a follow-up can arrive while `run` is awaited. */
136
+ followUpRequested() {
137
+ return this.rerunRequested;
138
+ }
139
+ async runOnce() {
140
+ try {
141
+ await this.run();
142
+ return null;
143
+ }
144
+ catch (error) {
145
+ this.onError(error);
146
+ return { error };
101
147
  }
102
148
  }
149
+ retryDelay(error, retryIndex) {
150
+ if (this.retry === undefined || retryIndex >= this.retry.maxRetries) {
151
+ return null;
152
+ }
153
+ let delayMs;
154
+ try {
155
+ delayMs = this.retry.delayMs(error, retryIndex);
156
+ }
157
+ catch (delayError) {
158
+ this.onError(delayError);
159
+ return null;
160
+ }
161
+ if (delayMs !== null && (!Number.isFinite(delayMs) || delayMs < 0)) {
162
+ this.onError(new RangeError('retry.delayMs must return a finite non-negative number'));
163
+ return null;
164
+ }
165
+ return delayMs;
166
+ }
167
+ /** The environment has interval timers only, so the delay clears its interval on the first tick. */
168
+ waitForRetry(delayMs) {
169
+ return new Promise((resolve) => {
170
+ const wake = (reason) => {
171
+ this.environment.clearInterval(timer);
172
+ if (this.wakeRetry === wake) {
173
+ this.wakeRetry = null;
174
+ }
175
+ resolve(reason);
176
+ };
177
+ const timer = this.environment.setInterval(() => {
178
+ wake('elapsed');
179
+ }, delayMs);
180
+ this.wakeRetry = wake;
181
+ });
182
+ }
103
183
  refreshInterval() {
104
184
  this.stopInterval();
105
185
  if (!this.started || !this.active) {
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baukit/sync-client",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Client-side scheduling, transport, status reporting, and ordering for offline-capable sync loops.",
5
5
  "license": "MIT",
6
6
  "author": "Patrick Koss",