wkdhkr/dedupper

View on GitHub
src/helpers/LockHelper.js

Summary

Maintainability
A
35 mins
Test Coverage
// @flow
import sleep from "await-sleep";
import os from "os";
import path from "path";
import lockFile from "lockfile";
import util from "util";

const lockFileAsync = util.promisify((lockFile: any).lock.bind(lockFile));

export default class LockHelper {
  static keyLockMap: { [string]: true } = {};

  static pollPeriod: number = 1000;

  static getLockFilePath(name: string): string {
    return path.join(os.tmpdir(), `dedupper.${name}.lock`);
  }

  static async lockKey(key: string, force: boolean = false) {
    if (key === "") {
      return;
    }
    let count = 1;
    while (LockHelper.keyLockMap[key]) {
      if (count === 60 * 10) {
        if (force) {
          return;
        }
        throw new Error(`key lock fail. key = ${key}`);
      }
      // eslint-disable-next-line no-await-in-loop
      await sleep(1000);
      count += 1;
    }
    LockHelper.keyLockMap[key] = true;
  }

  static unlockKey(key: string) {
    if (key === "") {
      return;
    }
    delete LockHelper.keyLockMap[key];
  }

  static lockProcessSync: (name?: string) => boolean = (
    name: string = "process"
  ) => {
    try {
      (lockFile: any).lockSync(this.getLockFilePath(name));
      return true;
    } catch (e) {
      return false;
    }
  };

  static lockProcess: (name?: string) => Promise<void> = async (
    name: string = "process"
  ): Promise<void> => {
    /*
    (lockFile: any).check(
      this.getLockFilePath(name),
      (checkError, isLocked: boolean) => {
        if (checkError || isLocked === false) {
          lockFile.lock(
            this.getLockFilePath(name),
            {
              wait: Infinity,
              pollPeriod: 1000
            },
            err => {
              if (err) {
                reject(err);
              }
              resolve();
            }
          );
        } else {
          resolve();
        }
      }
    );
    */
    try {
      await lockFileAsync(this.getLockFilePath(name), {
        wait: Infinity,
        stale: 1000 * 60 * 10, // 10 min
        pollPeriod: LockHelper.pollPeriod
      });
    } catch (e) {
      await this.lockProcess(name);
    }
  };

  static unlockProcess(name: string = "process"): Promise<void> {
    return new Promise(resolve => {
      lockFile.unlock(this.getLockFilePath(name), () => resolve());
    });
  }
}