summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2020-04-20 12:47:55 +0200
committerOskar Nyberg <oskar@mullvad.net>2020-04-21 08:12:39 +0200
commit8f837f09c5658dad894ee2b974af5316fc1cb0a9 (patch)
tree10ca160500ae939c8e30169f1d49f2143da2c762
parentdf99bc1790ac00a73a41e3449db79a12ee8fd72d (diff)
downloadmullvadvpn-8f837f09c5658dad894ee2b974af5316fc1cb0a9.tar.xz
mullvadvpn-8f837f09c5658dad894ee2b974af5316fc1cb0a9.zip
Add account data fetch lock to prevent simultaneos fetches
-rw-r--r--gui/src/main/account-data-cache.ts12
-rw-r--r--gui/test/account-data-cache.spec.ts1
2 files changed, 11 insertions, 2 deletions
diff --git a/gui/src/main/account-data-cache.ts b/gui/src/main/account-data-cache.ts
index 034ec5b379..f4864743a8 100644
--- a/gui/src/main/account-data-cache.ts
+++ b/gui/src/main/account-data-cache.ts
@@ -19,6 +19,7 @@ interface IAccountFetchWatcher {
export default class AccountDataCache {
private currentAccount?: AccountToken;
private expiresAt?: Date;
+ private performingFetch = false;
private fetchAttempt = 0;
private fetchRetryTimeout?: NodeJS.Timeout;
private watchers: IAccountFetchWatcher[] = [];
@@ -35,7 +36,7 @@ export default class AccountDataCache {
this.currentAccount = accountToken;
}
- // Only fetch is value has expired
+ // Only fetch if value has expired
if (this.isExpired()) {
if (watcher) {
this.watchers.push(watcher);
@@ -45,7 +46,10 @@ export default class AccountDataCache {
// If a scheduled retry is cancelled the fetchAttempt shouldn't be increased.
this.fetchAttempt = Math.max(0, this.fetchAttempt - 1);
- consumePromise(this.performFetch(accountToken));
+ // Only fetch if there's no fetch for this account number in progress.
+ if (!this.performingFetch) {
+ consumePromise(this.performFetch(accountToken));
+ }
} else if (watcher) {
watcher.onFinish();
}
@@ -55,6 +59,7 @@ export default class AccountDataCache {
this.clearFetchRetryTimeout();
this.fetchAttempt = 0;
+ this.performingFetch = false;
this.expiresAt = undefined;
this.updateHandler();
this.notifyWatchers((watcher) => {
@@ -80,6 +85,7 @@ export default class AccountDataCache {
}
private async performFetch(accountToken: AccountToken) {
+ this.performingFetch = true;
try {
// it's possible for invalidate() to be called or for a fetch for a different account token
// to start before this fetch completes, so checking if the current account token is the one
@@ -89,10 +95,12 @@ export default class AccountDataCache {
if (this.currentAccount === accountToken) {
this.setValue(accountData);
this.scheduleRefetchIfExpired(accountToken, accountData);
+ this.performingFetch = false;
}
} catch (error) {
if (this.currentAccount === accountToken) {
this.handleFetchError(accountToken, error);
+ this.performingFetch = false;
}
}
}
diff --git a/gui/test/account-data-cache.spec.ts b/gui/test/account-data-cache.spec.ts
index 7a485b878a..6839e7a1eb 100644
--- a/gui/test/account-data-cache.spec.ts
+++ b/gui/test/account-data-cache.spec.ts
@@ -258,6 +258,7 @@ describe('IAccountData cache', () => {
expect(updateHandler).to.have.been.called.twice;
});
});
+
it('should not perform a fetch if called twice synchronously', async () => {
const fetchSpy = spy();
const update = new Promise((resolve, _reject) => {