Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions CodePush.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AcquisitionManager as Sdk, DownloadStatus } from "./lib/commonjs/acquisition-sdk/acquisition-sdk";
import { onceUntilRejected } from "./lib/commonjs/once-until-rejected";
import { Alert } from "./AlertAdapter";
import requestFetchAdapter from "./request-fetch-adapter";
import { AppState, NativeEventEmitter, Platform } from "react-native";
Expand Down Expand Up @@ -312,18 +313,8 @@ function getPromisifiedSdk(requestFetchAdapter, config) {
return sdk;
}

// This ensures that notifyApplicationReadyInternal is only called once
// in the lifetime of this module instance.
const notifyApplicationReady = (() => {
let notifyApplicationReadyPromise;
return () => {
if (!notifyApplicationReadyPromise) {
notifyApplicationReadyPromise = notifyApplicationReadyInternal();
}

return notifyApplicationReadyPromise;
};
})();
// Succeeds once per module instance; a failed call is retried by the next caller (e.g. sync()).
const notifyApplicationReady = onceUntilRejected(notifyApplicationReadyInternal);

async function notifyApplicationReadyInternal() {
await NativeCodePush.notifyApplicationReady();
Expand Down
34 changes: 34 additions & 0 deletions src/__tests__/once-until-rejected.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as assert from 'assert';

import { onceUntilRejected } from '../once-until-rejected';

describe('onceUntilRejected', () => {
it('does not run again after it resolves', async () => {
let calls = 0;
const run = onceUntilRejected(async () => ++calls);

assert.strictEqual(await run(), 1);
assert.strictEqual(await run(), 1);
assert.strictEqual(calls, 1);
});

it('shares a pending attempt, and runs again after it rejects', async () => {
let calls = 0;
const run = onceUntilRejected(async () => {
calls++;
if (calls === 1) {
throw new Error('first attempt failed');
}
return calls;
});

const first = run();
const second = run();
assert.strictEqual(first, second);
await assert.rejects(first, /first attempt failed/);

assert.strictEqual(await run(), 2);
assert.strictEqual(await run(), 2);
assert.strictEqual(calls, 2);
});
});
13 changes: 13 additions & 0 deletions src/once-until-rejected.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Dedupes concurrent and repeat calls, but forgets a rejected attempt so a transient failure isn't permanent.
export function onceUntilRejected<T>(fn: () => Promise<T>): () => Promise<T> {
let promise: Promise<T> | undefined;
return () => {
if (!promise) {
promise = fn().catch((error) => {
promise = undefined;
throw error;
});
}
return promise;
};
}
Loading