Add withlock function with timeout

This commit is contained in:
Oliver Blanthorn 2020-02-29 19:43:38 +00:00
parent 6f6c9e0cd0
commit 84d258c293
No known key found for this signature in database
GPG key ID: 2BB8C36BB504BFF3

View file

@ -2,6 +2,9 @@
import {messageAllTabs} from "@src/lib/messaging"
import {v1 as uuid} from "uuid"
import * as Logging from "@src/lib/logging"
const logger = new Logging.Logger("locks")
export const OWNED_LOCKS = new Set()
@ -11,24 +14,41 @@ export const ID = uuid()
const now = () => (new Date()).getTime() + Math.random() // getTime is accurate only to ms, so fake microseconds with random
export async function acquire(lockname: string, timeout= 2000) {
export async function acquire(lockname: string) {
if (OWNED_LOCKS.has(lockname) || DESIRED_LOCKS.hasOwnProperty(lockname)) return;
const time = now()
DESIRED_LOCKS[lockname] = time
await Promise.race([
Promise.all([
browser.runtime.sendMessage({type: "lock", command: "acquire", args: [lockname, time, ID]}),
messageAllTabs("lock", "acquire", [lockname, time, ID]),
]),
new Promise(resolve => setTimeout(resolve, timeout)), // Take lock anyway after timeout
await Promise.all([
browser.runtime.sendMessage({type: "lock", command: "acquire", args: [lockname, time, ID]}),
messageAllTabs("lock", "acquire", [lockname, time, ID]),
])
delete DESIRED_LOCKS[lockname]
OWNED_LOCKS.add(lockname)
}
/**
* Execute func after acquiring a named lock. If func takes longer than timeout, release the lock early.
* Returns the value of func.
*/
export async function withlock(lockname: string, func, timeout= 2000) {
await acquire(lockname)
const p = (async () => func())() // Ensure function is promisified
const a = await Promise.race([
p,
new Promise(resolve => setTimeout(
() => {
resolve("ERROR: LOST THE RACE")
},
timeout)), // Release the lock anyway after timeout
])
if (a === "ERROR: LOST THE RACE") {logger.warning("lock " + lockname + " was released early")}
release(lockname)
return p
}
export async function release(lockname: string) {
OWNED_LOCKS.delete(lockname)
}