MCPcopy Create free account
hub / github.com/MoonshotAI/kimi-code / acquireLock

Function acquireLock

packages/server/src/lock.ts:193–246  ·  view source on GitHub ↗
(opts: AcquireLockOptions)

Source from the content-addressed store, hash-verified

191 * recorded pid is no longer running.
192 */
193export function acquireLock(opts: AcquireLockOptions): AcquireLockResult {
194 const lockPath = opts.lockPath ?? DEFAULT_LOCK_PATH;
195 const pid = opts.pid ?? process.pid;
196 const startedAt = opts.nowIso ?? new Date().toISOString();
197 const contents: LockContents = {
198 pid,
199 started_at: startedAt,
200 host: opts.host,
201 port: opts.port,
202 ...(opts.hostVersion !== undefined ? { host_version: opts.hostVersion } : {}),
203 ...(opts.entry !== undefined ? { entry: opts.entry } : {}),
204 };
205
206 mkdirSync(dirname(lockPath), { recursive: true });
207
208 // First try: clean acquire.
209 if (tryExclusiveCreate(lockPath, contents)) {
210 return makeReleaseHandle(lockPath, pid);
211 }
212
213 // Lock exists — inspect.
214 const existing = readLockContents(lockPath);
215 if (existing && pidAlive(existing.pid)) {
216 // Live owner — refuse to take over. Note that "same pid as ours" still
217 // counts as live: callers that genuinely want to swap should release the
218 // existing handle first, not stomp via acquireLock.
219 throw new ServerLockedError(
220 `server already running (pid=${existing.pid}, port=${existing.port}, started=${existing.started_at})`,
221 existing,
222 );
223 }
224
225 // Stale (dead pid) or unparseable — take over.
226 try {
227 unlinkSync(lockPath);
228 } catch (err) {
229 // EBUSY/ENOENT both acceptable — race with another concurrent acquirer.
230 if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
231 throw err;
232 }
233 }
234
235 if (!tryExclusiveCreate(lockPath, contents)) {
236 // Someone slipped in. Re-read for diagnostic.
237 const winner = readLockContents(lockPath);
238 throw new ServerLockedError(
239 winner
240 ? `server already running (pid=${winner.pid}, port=${winner.port}, started=${winner.started_at})`
241 : 'lock file present but unreadable',
242 winner ?? { pid: -1, started_at: '', port: opts.port },
243 );
244 }
245 return makeReleaseHandle(lockPath, pid);
246}
247
248function makeReleaseHandle(lockPath: string, ownerPid: number): AcquireLockResult {
249 let released = false;

Callers 2

lock.test.tsFile · 0.90
startServerFunction · 0.90

Calls 4

tryExclusiveCreateFunction · 0.85
makeReleaseHandleFunction · 0.85
readLockContentsFunction · 0.85
pidAliveFunction · 0.70

Tested by

no test coverage detected