@digigov-oss/gsis-audit-record-db
Version:
JSON file storage database for use with audit mechanism of GSIS
92 lines (81 loc) • 2.78 kB
text/typescript
import fs from 'fs';
import { FS_ERROR } from '../../interfaces/index.js';
const LOCK_FILE_PATH = "/tmp/sequence"
const SEQUENCE_FILE = "/tmp/sequence"
/**
* timeout for lock file, we will try to delete it after timeout, in case was not deleted on previous run
* you can increase this value if you have a lot of processes running on the same machine
* @type {number}
* @env TIMEOUT_LOCK_FILE
*/
const TIMEOUT_LOCK_FILE: number = (process.env.TIMEOUT_LOCK_FILE ? ~~process.env.TIMEOUT_LOCK_FILE : undefined) || 10000;
/**
* set delay in ms
* @param ms
* @returns Promise<void>
*/
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
/**
* create a lock file
* @param path
* @param timeout
* @returns Promise<number>
*/
const lockFile = async (path: string, timeout: number = 0): Promise<number> => {
//TODO if the file exists for long time have to delete it
// because probably something is broken on previous run
// this works but may be not the best solution
if (timeout++ > TIMEOUT_LOCK_FILE) { console.log(timeout, " times loop, try to unlock"); await delay(1000); unlockFile(path) };
const lockPath = `${path}.lock`
try {
return fs.openSync(lockPath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_RDWR)
} catch (error) {
const err: FS_ERROR = error as FS_ERROR;
if (err.code !== "EEXIST") console.log(err.message);
return lockFile(path, timeout)
}
}
/**
* unlink the lock file
* @param path
* @param timeout
* @returns Promise<void>
*/
const unlockFile = async (path: string, timeout: number = 0): Promise<void> => {
const lockPath = `${path}.lock`
if (timeout++ > TIMEOUT_LOCK_FILE) { console.log(timeout, " times loop, unlock exit"); return };
try {
return fs.unlinkSync(lockPath)
}
catch (error) {
const err: FS_ERROR = error as FS_ERROR;
if (err.code === "ENOENT") {
return;
} else {
console.log(err.message);
await delay(500);
return unlockFile(path, timeout++);
}
}
}
/**
* update the sequence number on giveb sequence file
* @param seqfile
* @param lockfile
* @returns number
*/
const sequence = (seqfile: string = "", lockfile: string = ""): number => {
let SEQF = SEQUENCE_FILE;
let LFP = LOCK_FILE_PATH;
if (seqfile !== "") SEQF = seqfile;
if (lockfile !== "") LFP = lockfile;
if (!fs.existsSync(SEQF)) {
fs.writeFileSync(SEQF, "0")
}
const abla = lockFile(LFP);
let seq: number = ~~fs.readFileSync(SEQF); //Read as integer ~~ is synonimus for parseInt
fs.writeFileSync(SEQF, "" + ++seq);
const oubla = unlockFile(LFP);
return seq;
}
export default sequence;