Skip to content

Commit

Permalink
userId: fix unhandled rejection from refreshUserIds (#12246)
Browse files Browse the repository at this point in the history
* userId: fix unhandled rejection from refreshUserIds

* apply same treatment to getEncryptedEidsForSource
  • Loading branch information
dgirardi authored Sep 23, 2024
1 parent a4822db commit d693107
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 29 deletions.
40 changes: 22 additions & 18 deletions modules/userId/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ function getUserIdsAsEidBySource(sourceName) {
* Sample use case is exposing this function to ESP
*/
function getEncryptedEidsForSource(source, encrypt, customFunction) {
return initIdSystem().then(() => {
return retryOnCancel().then(() => {
let eidsSignals = {};

if (isFn(customFunction)) {
Expand Down Expand Up @@ -782,6 +782,23 @@ function registerSignalSources() {
}
}

function retryOnCancel(initParams) {
return initIdSystem(initParams).then(
() => getUserIds(),
(e) => {
if (e === INIT_CANCELED) {
// there's a pending refresh - because GreedyPromise runs this synchronously, we are now in the middle
// of canceling the previous init, before the refresh logic has had a chance to run.
// Use a "normal" Promise to clear the stack and let it complete (or this will just recurse infinitely)
return Promise.resolve().then(getUserIdsAsync)
} else {
logError('Error initializing userId', e)
return GreedyPromise.reject(e)
}
}
);
}

/**
* Force (re)initialization of ID submodules.
*
Expand All @@ -793,12 +810,12 @@ function registerSignalSources() {
* @param callback? called when the refresh is complete
*/
function refreshUserIds({submoduleNames} = {}, callback) {
return initIdSystem({refresh: true, submoduleNames})
.then(() => {
return retryOnCancel({refresh: true, submoduleNames})
.then((userIds) => {
if (callback && isFn(callback)) {
callback();
}
return getUserIds();
return userIds;
});
}

Expand All @@ -814,20 +831,7 @@ function refreshUserIds({submoduleNames} = {}, callback) {
*/

function getUserIdsAsync() {
return initIdSystem().then(
() => getUserIds(),
(e) => {
if (e === INIT_CANCELED) {
// there's a pending refresh - because GreedyPromise runs this synchronously, we are now in the middle
// of canceling the previous init, before the refresh logic has had a chance to run.
// Use a "normal" Promise to clear the stack and let it complete (or this will just recurse infinitely)
return Promise.resolve().then(getUserIdsAsync)
} else {
logError('Error initializing userId', e)
return GreedyPromise.reject(e)
}
}
);
return retryOnCancel();
}

export function getConsentHash() {
Expand Down
24 changes: 13 additions & 11 deletions test/spec/modules/userId_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1102,18 +1102,20 @@ describe('User ID', function () {
});
});

it('should still resolve promises returned by getUserIdsAsync', () => {
startInit();
let result = null;
getGlobal().getUserIdsAsync().then((val) => { result = val; });
return clearStack().then(() => {
expect(result).to.equal(null); // auction has not ended, callback should not have been called
mockIdCallback.callsFake((cb) => cb(MOCK_ID));
return getGlobal().refreshUserIds().then(clearStack);
}).then(() => {
expect(result).to.deep.equal(getGlobal().getUserIds()) // auction still not over, but refresh was explicitly forced
['refreshUserIds', 'getUserIdsAsync'].forEach(method => {
it(`should still resolve promises returned by ${method}`, () => {
startInit();
let result = null;
getGlobal()[method]().then((val) => { result = val; });
return clearStack().then(() => {
expect(result).to.equal(null); // auction has not ended, callback should not have been called
mockIdCallback.callsFake((cb) => cb(MOCK_ID));
return getGlobal().refreshUserIds().then(clearStack);
}).then(() => {
expect(result).to.deep.equal(getGlobal().getUserIds()) // auction still not over, but refresh was explicitly forced
});
});
});
})

it('should not stop auctions', (done) => {
// simulate an infinite `auctionDelay`; refreshing should still allow the auction to continue
Expand Down

0 comments on commit d693107

Please sign in to comment.