@mtdt.temp/browser-core
Version:
Datadog browser core utilities.
123 lines • 5.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LOCK_EXPIRATION_DELAY = exports.LOCK_MAX_TRIES = exports.LOCK_RETRY_DELAY = void 0;
exports.processSessionStoreOperations = processSessionStoreOperations;
exports.createLock = createLock;
const timer_1 = require("../../tools/timer");
const stringUtils_1 = require("../../tools/utils/stringUtils");
const timeUtils_1 = require("../../tools/utils/timeUtils");
const telemetry_1 = require("../telemetry");
const sessionState_1 = require("./sessionState");
exports.LOCK_RETRY_DELAY = 10;
exports.LOCK_MAX_TRIES = 100;
// Locks should be hold for a few milliseconds top, just the time it takes to read and write a
// cookie. Using one second should be enough in most situations.
exports.LOCK_EXPIRATION_DELAY = timeUtils_1.ONE_SECOND;
const LOCK_SEPARATOR = '--';
const bufferedOperations = [];
let ongoingOperations;
function processSessionStoreOperations(operations, sessionStoreStrategy, numberOfRetries = 0) {
var _a;
const { isLockEnabled, persistSession, expireSession } = sessionStoreStrategy;
const persistWithLock = (session) => persistSession({ ...session, lock: currentLock });
const retrieveStore = () => {
const { lock, ...session } = sessionStoreStrategy.retrieveSession();
return {
session,
lock: lock && !isLockExpired(lock) ? lock : undefined,
};
};
if (!ongoingOperations) {
ongoingOperations = operations;
}
if (operations !== ongoingOperations) {
bufferedOperations.push(operations);
return;
}
if (isLockEnabled && numberOfRetries >= exports.LOCK_MAX_TRIES) {
(0, telemetry_1.addTelemetryDebug)('Aborted session operation after max lock retries', {
currentStore: retrieveStore(),
});
next(sessionStoreStrategy);
return;
}
let currentLock;
let currentStore = retrieveStore();
if (isLockEnabled) {
// if someone has lock, retry later
if (currentStore.lock) {
retryLater(operations, sessionStoreStrategy, numberOfRetries);
return;
}
// acquire lock
currentLock = createLock();
persistWithLock(currentStore.session);
// if lock is not acquired, retry later
currentStore = retrieveStore();
if (currentStore.lock !== currentLock) {
retryLater(operations, sessionStoreStrategy, numberOfRetries);
return;
}
}
let processedSession = operations.process(currentStore.session);
if (isLockEnabled) {
// if lock corrupted after process, retry later
currentStore = retrieveStore();
if (currentStore.lock !== currentLock) {
retryLater(operations, sessionStoreStrategy, numberOfRetries);
return;
}
}
if (processedSession) {
if ((0, sessionState_1.isSessionInExpiredState)(processedSession)) {
expireSession(processedSession);
}
else {
(0, sessionState_1.expandSessionState)(processedSession);
if (isLockEnabled) {
persistWithLock(processedSession);
}
else {
persistSession(processedSession);
}
}
}
if (isLockEnabled) {
// correctly handle lock around expiration would require to handle this case properly at several levels
// since we don't have evidence of lock issues around expiration, let's just not do the corruption check for it
if (!(processedSession && (0, sessionState_1.isSessionInExpiredState)(processedSession))) {
// if lock corrupted after persist, retry later
currentStore = retrieveStore();
if (currentStore.lock !== currentLock) {
retryLater(operations, sessionStoreStrategy, numberOfRetries);
return;
}
persistSession(currentStore.session);
processedSession = currentStore.session;
}
}
// call after even if session is not persisted in order to perform operations on
// up-to-date session state value => the value could have been modified by another tab
(_a = operations.after) === null || _a === void 0 ? void 0 : _a.call(operations, processedSession || currentStore.session);
next(sessionStoreStrategy);
}
function retryLater(operations, sessionStore, currentNumberOfRetries) {
(0, timer_1.setTimeout)(() => {
processSessionStoreOperations(operations, sessionStore, currentNumberOfRetries + 1);
}, exports.LOCK_RETRY_DELAY);
}
function next(sessionStore) {
ongoingOperations = undefined;
const nextOperations = bufferedOperations.shift();
if (nextOperations) {
processSessionStoreOperations(nextOperations, sessionStore);
}
}
function createLock() {
return (0, stringUtils_1.generateUUID)() + LOCK_SEPARATOR + (0, timeUtils_1.timeStampNow)();
}
function isLockExpired(lock) {
const [, timeStamp] = lock.split(LOCK_SEPARATOR);
return !timeStamp || (0, timeUtils_1.elapsed)(Number(timeStamp), (0, timeUtils_1.timeStampNow)()) > exports.LOCK_EXPIRATION_DELAY;
}
//# sourceMappingURL=sessionStoreOperations.js.map