Standalone projects and library code don't get a Document Lock. When the critical section is the script project itself — watermark updates, Script Properties, a shared import cursor — wrap it with LockService.getScriptLock() and always unlock in finally.
What you'll need
- A critical section that should serialize across all users / all installs of this project (or the standalone script)
- Contrast with
withDocumentLock(bound spreadsheet) andwithUserLock(per-user only)
Why Script Lock
| Lock | Serializes |
|---|---|
| Document | Everyone on this spreadsheet |
| User | The same user's overlapping runs |
| Script | Anyone running this project / library |
Use Script Lock for standalone web apps, libraries, and property-store races that aren't tied to one bound file.
How to use this snippet
function withScriptLock(fn, waitMs) {
waitMs = waitMs || 30000;
var lock = LockService.getScriptLock();
if (!lock.tryLock(waitMs)) {
throw new Error('Could not acquire script lock within ' + waitMs + 'ms');
}
try {
return fn();
} finally {
lock.releaseLock();
}
}
function bumpImportCursor(nextValue) {
return withScriptLock(function () {
var props = PropertiesService.getScriptProperties();
var current = Number(props.getProperty('importCursor') || '0');
if (nextValue <= current) return current; // already advanced
props.setProperty('importCursor', String(nextValue));
return nextValue;
});
}
Tips:
- Same try/finally discipline as the document/user helpers — a thrown error must still
releaseLock. - Keep UrlFetch and other slow I/O outside the lock when you can; hold it only for the read-modify-write.
- Fail loud when
tryLockreturns false — silent skips look like successful runs.
Happy Coding!
