-
Notifications
You must be signed in to change notification settings - Fork 56
Promote dev to stable: PM2 Genie install recovery #2476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -117,6 +117,12 @@ interface Pm2Process { | |||||||||||||
| pm2_env?: { status?: string }; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| function isReusableCanonicalPm2Process(process: Pm2Process | null): boolean { | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The parameter name process shadows the global process object in Node.js. While TypeScript allows this, it is a common source of confusion and potential bugs if someone later tries to access global properties like process.env or process.exit() within this function. Consider renaming it to pm2Process or proc to improve maintainability and clarity.
Suggested change
|
||||||||||||||
| if (!process) return false; | ||||||||||||||
| if (process.pm2_env?.status !== 'online') return false; | ||||||||||||||
| return typeof process.pid === 'number' && process.pid > 0; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| function pm2GetProcess(name: string): Pm2Process | null { | ||||||||||||||
| try { | ||||||||||||||
| const out = execFileSync('pm2', ['jlist'], { | ||||||||||||||
|
|
@@ -154,17 +160,21 @@ function pm2GetAnyProcess(names: readonly string[]): Pm2Process | null { | |||||||||||||
| * a manual cleanup to do (`pm2 delete <legacy-name>`) but do not abort | ||||||||||||||
| * install over it. | ||||||||||||||
| */ | ||||||||||||||
| function deletePm2Process(name: string): void { | ||||||||||||||
| execFileSync('pm2', ['delete', name], { | ||||||||||||||
| encoding: 'utf8', | ||||||||||||||
| timeout: 10_000, | ||||||||||||||
| stdio: ['ignore', 'pipe', 'pipe'], | ||||||||||||||
| }); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| function removeLegacyPm2Entries(log: (msg: string) => void = () => {}): string[] { | ||||||||||||||
| const removed: string[] = []; | ||||||||||||||
| for (const legacyName of LEGACY_PM2_PROCESS_NAMES) { | ||||||||||||||
| const existing = pm2GetProcess(legacyName); | ||||||||||||||
| if (!existing) continue; | ||||||||||||||
| try { | ||||||||||||||
| execFileSync('pm2', ['delete', legacyName], { | ||||||||||||||
| encoding: 'utf8', | ||||||||||||||
| timeout: 10_000, | ||||||||||||||
| stdio: ['ignore', 'pipe', 'pipe'], | ||||||||||||||
| }); | ||||||||||||||
| deletePm2Process(legacyName); | ||||||||||||||
| log(`removed legacy pm2 entry "${legacyName}" (renamed to "${PM2_PROCESS_NAME}")`); | ||||||||||||||
| removed.push(legacyName); | ||||||||||||||
| } catch (err) { | ||||||||||||||
|
|
@@ -570,10 +580,23 @@ export async function installCommand(options: InstallOptions = {}): Promise<void | |||||||||||||
| // Step 3 — pm2-supervise the canonical Genie service. | ||||||||||||||
| const existing = pm2GetProcess(PM2_PROCESS_NAME); | ||||||||||||||
| if (existing) { | ||||||||||||||
| if (isReusableCanonicalPm2Process(existing)) { | ||||||||||||||
| ok( | ||||||||||||||
| `already installed (pm2 process "${PM2_PROCESS_NAME}", status=${existing.pm2_env?.status ?? 'unknown'}). Use \`pm2 delete ${PM2_PROCESS_NAME} && genie install\` to refresh the env (e.g. to pick up a new canonical pgserve URL).`, | ||||||||||||||
| ); | ||||||||||||||
| return; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| const status = existing.pm2_env?.status ?? 'unknown'; | ||||||||||||||
| ok( | ||||||||||||||
| `already installed (pm2 process "${PM2_PROCESS_NAME}", status=${existing.pm2_env?.status ?? 'unknown'}). Use \`pm2 delete ${PM2_PROCESS_NAME} && genie install\` to refresh the env (e.g. to pick up a new canonical pgserve URL).`, | ||||||||||||||
| `pm2 process "${PM2_PROCESS_NAME}" exists but is not reusable (status=${status}, pid=${existing.pid ?? 'none'}); recreating`, | ||||||||||||||
| ); | ||||||||||||||
| return; | ||||||||||||||
| try { | ||||||||||||||
| deletePm2Process(PM2_PROCESS_NAME); | ||||||||||||||
| } catch (err) { | ||||||||||||||
| const reason = err instanceof Error ? err.message : String(err); | ||||||||||||||
| fail(`pm2 process "${PM2_PROCESS_NAME}" is unhealthy and pm2 delete failed: ${reason}`); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| ensureLogsDir(); | ||||||||||||||
|
|
@@ -641,4 +664,5 @@ export const _internals = { | |||||||||||||
| isPgservePm2ManagedStatus, | ||||||||||||||
| isPgserveReadyStatus, | ||||||||||||||
| isPgserveOnlinePm2, | ||||||||||||||
| isReusableCanonicalPm2Process, | ||||||||||||||
| }; | ||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Block release bump until SHA drift is resolved.
4.260522.9should not be promoted while Binary SHA Drift is failing; this breaks release integrity checks tied tobinarySha256in this manifest. Update pinned SHA(s) and fix the unknown asset-prefix handling before merging this version bump.🧰 Tools
🪛 GitHub Actions: Binary SHA Drift / drift-check
[error] SHA drift detected for pinned binarySha256 asset (message: "SHA drift for $asset"). Upstream binary SHA256 does not match the pinned value in package.json.
[warning] Unknown asset prefix '$asset' — skipping drift check for this asset (extend drift check to support it).
🤖 Prompt for AI Agents