Merge pull request #11 from defunkt/claude/fix-app-rename-shutdown-IzD79

Make renameApp async and fix race condition on app restart
This commit is contained in:
Chris Wanstrath 2026-02-12 08:15:35 -08:00 committed by GitHub
commit f0bef491a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 9 additions and 7 deletions

View File

@ -229,7 +229,7 @@ router.post('/:app/rename', async c => {
if (!newName) return c.json({ ok: false, error: 'New name is required' }, 400) if (!newName) return c.json({ ok: false, error: 'New name is required' }, 400)
const result = renameApp(appName, newName) const result = await renameApp(appName, newName)
if (!result.ok) return c.json(result, 400) if (!result.ok) return c.json(result, 400)
return c.json({ ok: true, name: newName }) return c.json({ ok: true, name: newName })

View File

@ -142,7 +142,7 @@ export function registerApp(dir: string) {
} }
} }
export function renameApp(oldName: string, newName: string): { ok: boolean, error?: string } { export async function renameApp(oldName: string, newName: string): Promise<{ ok: boolean, error?: string }> {
const app = _apps.get(oldName) const app = _apps.get(oldName)
if (!app) return { ok: false, error: 'App not found' } if (!app) return { ok: false, error: 'App not found' }
@ -155,15 +155,13 @@ export function renameApp(oldName: string, newName: string): { ok: boolean, erro
const oldPath = join(APPS_DIR, oldName) const oldPath = join(APPS_DIR, oldName)
const newPath = join(APPS_DIR, newName) const newPath = join(APPS_DIR, newName)
// Stop the app if running // Stop the app and wait for process to fully exit so the port is freed
const wasRunning = app.state === 'running' const wasRunning = app.state === 'running'
if (wasRunning) { if (wasRunning) {
const proc = app.proc
clearTimers(app) clearTimers(app)
app.proc?.kill() app.proc?.kill()
app.proc = undefined if (proc) await proc.exited
if (app.port) releasePort(app.port)
app.port = undefined
app.started = undefined
} }
try { try {
@ -681,6 +679,10 @@ async function runApp(dir: string, port: number) {
// Handle process exit // Handle process exit
proc.exited.then(code => { proc.exited.then(code => {
// If the app has moved on (e.g. renamed and restarted), this is a
// stale exit handler — don't touch current app state or ports
if (app.proc && app.proc !== proc) return
// Clear all timers // Clear all timers
clearTimers(app) clearTimers(app)