Don't schedule multiple token refreshes for the same user/realm (#2071)
* Don't schedule multiple token refreshes for the same user/realm * Avoid setting a const property
This commit is contained in:
parent
cf1632eb0f
commit
10f72c5444
|
@ -1,11 +1,11 @@
|
|||
x.x.x Release notes (yyyy-MM-dd)
|
||||
=============================================================
|
||||
### Enhancements
|
||||
* None.
|
||||
* Improved the proactive token refresh mechanism to make several attempts to refresh the token before it expires and to also ensure that there is only one ongoing refresh timer for a combination of user and realm path. Previously it was possible to end up in a situation where many redundant refreshes were scheduled for the same Realm. ([#2071](https://github.com/realm/realm-js/pull/2071), since v1.0.2)
|
||||
|
||||
### Fixes
|
||||
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-js/issues/????), since v?.?.?)
|
||||
* None.
|
||||
* Fixed the signature of `user.logout` to return a `Promise<void>` rather than `void`. It has always done asynchronous work, but previously, it was impossible to be notified that the call has completed. Since that is now possible, the superfluous "User is logged out" message printed in the console upon logout has been removed. ([#2071](https://github.com/realm/realm-js/pull/2071), since v2.3.0)
|
||||
|
||||
### Compatibility
|
||||
* Realm Object Server: 3.11.0 or later.
|
||||
|
|
|
@ -524,7 +524,9 @@ class User {
|
|||
serialize() {}
|
||||
|
||||
/**
|
||||
* Logs out the user from the Realm Object Server.
|
||||
* Logs out the user from the Realm Object Server. Once the Object Server has confirmed the logout the user
|
||||
* credentials will be deleted from this device.
|
||||
* @return {Promise<void>} A promise which is resolved when the user has logged out both locally and on the server.
|
||||
*/
|
||||
logout() {}
|
||||
|
||||
|
|
|
@ -337,7 +337,7 @@ declare namespace Realm.Sync {
|
|||
|
||||
createConfiguration(config?: Realm.PartialConfiguration): Realm.Configuration
|
||||
serialize(): SerializedUser;
|
||||
logout(): void;
|
||||
logout(): Promise<void>;
|
||||
openManagementRealm(): Realm;
|
||||
retrieveAccount(provider: string, username: string): Promise<Account>;
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@ const merge = require('deepmerge');
|
|||
const require_method = require;
|
||||
const URL = require('url-parse');
|
||||
|
||||
const refreshTimers = {};
|
||||
const retryInterval = 5 * 1000;
|
||||
const refreshBuffer = 20 * 1000;
|
||||
|
||||
function node_require(module) {
|
||||
return require_method(module);
|
||||
}
|
||||
|
@ -107,9 +111,20 @@ function append_url(server, path) {
|
|||
}
|
||||
|
||||
function scheduleAccessTokenRefresh(user, localRealmPath, realmUrl, expirationDate) {
|
||||
const refreshBuffer = 10 * 1000;
|
||||
const timeout = expirationDate - Date.now() - refreshBuffer;
|
||||
setTimeout(() => refreshAccessToken(user, localRealmPath, realmUrl), timeout);
|
||||
let userTimers = refreshTimers[user.identity];
|
||||
if (!userTimers) {
|
||||
refreshTimers[user.identity] = userTimers = {};
|
||||
}
|
||||
|
||||
// We assume that access tokens have ~ the same expiration time, so if someone already
|
||||
// scheduled a refresh, it's likely to complete before the one we would have scheduled
|
||||
if (!userTimers[localRealmPath]) {
|
||||
const timeout = expirationDate - Date.now() - refreshBuffer;
|
||||
userTimers[localRealmPath] = setTimeout(() => {
|
||||
delete userTimers[localRealmPath];
|
||||
refreshAccessToken(user, localRealmPath, realmUrl);
|
||||
}, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
function print_error() {
|
||||
|
@ -177,7 +192,7 @@ function refreshAdminToken(user, localRealmPath, realmUrl) {
|
|||
})
|
||||
.catch((e) => {
|
||||
print_error(e);
|
||||
setTimeout(() => refreshAccessToken(user, localRealmPath, realmUrl), 10 * 1000);
|
||||
setTimeout(() => refreshAccessToken(user, localRealmPath, realmUrl), retryInterval);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -239,7 +254,7 @@ function refreshAccessToken(user, localRealmPath, realmUrl) {
|
|||
.catch((e) => {
|
||||
print_error(e);
|
||||
// in case something lower in the HTTP stack breaks, try again in 10 seconds
|
||||
setTimeout(() => refreshAccessToken(user, localRealmPath, realmUrl), 10 * 1000);
|
||||
setTimeout(() => refreshAccessToken(user, localRealmPath, realmUrl), retryInterval);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -498,6 +513,15 @@ const staticMethods = {
|
|||
const instanceMethods = {
|
||||
logout() {
|
||||
this._logout();
|
||||
const userTimers = refreshTimers[this.identity];
|
||||
if (userTimers) {
|
||||
Object.keys(userTimers).forEach((key) => {
|
||||
clearTimeout(userTimers[key]);
|
||||
});
|
||||
|
||||
delete refreshTimers[this.identity];
|
||||
}
|
||||
|
||||
const url = url_parse(this.server);
|
||||
url.set('pathname', '/auth/revoke');
|
||||
const headers = {
|
||||
|
@ -513,9 +537,8 @@ const instanceMethods = {
|
|||
open_timeout: 5000
|
||||
};
|
||||
|
||||
performFetch(url.href, options)
|
||||
.then(() => console.log('User is logged out'))
|
||||
.catch((e) => print_error(e));
|
||||
return performFetch(url.href, options)
|
||||
.catch((e) => print_error('An error occurred while logging out a user', e));
|
||||
},
|
||||
serialize() {
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue