diff options
Diffstat (limited to 'src/nwc-bg.js')
| -rw-r--r-- | src/nwc-bg.js | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/src/nwc-bg.js b/src/nwc-bg.js index 2c73206..ab083d9 100644 --- a/src/nwc-bg.js +++ b/src/nwc-bg.js @@ -81,6 +81,38 @@ export async function readBgLog() { export async function clearBgLog() { return tx('readwrite', (s) => { s.delete(LOG_KEY); }); } +// A lease on the worker's wallet work, kept in this store. Two pushes seconds +// apart ran side by side on iOS, each in its own worker (two "worker started" +// lines), and nothing kept them apart: both finished one send, and the +// second, over a stale copy, marked a paid send 'revoking'. The store is +// the one thing both see, and a readwrite transaction is atomic across them. +// A lease outlives a stopped worker only for its ttl. +export async function takeLease(name, { ttl = 12_000, wait = 5_000 } = {}) { + const key = '__lease:' + name; + const me = Math.random().toString(36).slice(2); + const start = Date.now(); + for (;;) { + let got = false; + try { + got = await tx('readwrite', async (s) => { + const cur = await get(s, key); + if (cur && cur.until > Date.now() && cur.owner !== me) return false; + s.put({ owner: me, until: Date.now() + ttl }, key); + return true; + }); + } catch { got = true; } // no store, no lease: run + if (got) break; + if (Date.now() - start > wait) break; // a holder that overstays: go anyway + await new Promise((r) => setTimeout(r, 250)); + } + const waited = Date.now() - start; + const release = () => tx('readwrite', async (s) => { + const cur = await get(s, key); + if (cur && cur.owner === me) s.delete(key); + }).catch(() => {}); + return { waited, release }; +} + // The service worker doesn't know wallet cache keys — it finds the right // record by the connection's service pubkey across all of them. export async function allBgs() { |
