Budibase is an open-source low-code platform for creating internal apps in minutes. Supports PostgreSQL, MySQL, MSSQL, MongoDB, Rest API, Docker, K8s 🚀
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

99 lines
2.3 KiB

import { split } from 'lodash/fp';
import { $ } from './index';
const lockOverlapMilliseconds = 10;
export const getLock = async (app, lockFile, timeoutMilliseconds, maxLockRetries, retryCount = 0) => {
try {
const timeout = (await app.getEpochTime())
+ timeoutMilliseconds;
const lock = {
timeout,
key: lockFile,
totalTimeout: timeoutMilliseconds,
};
await app.datastore.createFile(
lockFile,
getLockFileContent(
lock.totalTimeout,
lock.timeout,
),
);
return lock;
} catch (e) {
if (retryCount == maxLockRetries) { return NO_LOCK; }
const lock = parseLockFileContent(
lockFile,
await app.datastore.loadFile(lockFile),
);
const currentEpochTime = await app.getEpochTime();
if (currentEpochTime < lock.timeout) {
return NO_LOCK;
}
try {
await app.datastore.deleteFile(lockFile);
} catch (_) {
//empty
}
await sleepForRetry();
return await getLock(
app, lockFile, timeoutMilliseconds,
maxLockRetries, retryCount + 1,
);
}
};
export const getLockFileContent = (totalTimeout, epochTime) => `${totalTimeout}:${epochTime.toString()}`;
const parseLockFileContent = (key, content) => $(content, [
split(':'),
parts => ({
totalTimeout: new Number(parts[0]),
timeout: new Number(parts[1]),
key,
}),
]);
export const releaseLock = async (app, lock) => {
const currentEpochTime = await app.getEpochTime();
// only release if not timedout
if (currentEpochTime < (lock.timeout - lockOverlapMilliseconds)) {
try {
await app.datastore.deleteFile(lock.key);
} catch (_) {
//empty
}
}
};
export const extendLock = async (app, lock) => {
const currentEpochTime = await app.getEpochTime();
// only release if not timedout
if (currentEpochTime < (lock.timeout - lockOverlapMilliseconds)) {
try {
lock.timeout = currentEpochTime + lock.timeoutMilliseconds;
await app.datastore.updateFile(
lock.key,
getLockFileContent(lock.totalTimeout, lock.timeout),
);
return lock;
} catch (_) {
//empty
}
}
return NO_LOCK;
};
export const NO_LOCK = 'no lock';
export const isNolock = id => id === NO_LOCK;
const sleepForRetry = () => new Promise(resolve => setTimeout(resolve, lockOverlapMilliseconds));