Skip to content

Conversation

@truehazker
Copy link
Owner

@truehazker truehazker commented Dec 1, 2025

  • Add @types/pg for better type-safety
  • Refactor shutdown process in main.ts to use async/await for app and database termination.

Summary by CodeRabbit

  • Chores

    • Updated development dependencies.
  • Bug Fixes

    • Improved shutdown so the application stops services and closes connections cleanly; shutdown errors are logged and result in a non-zero exit and a forced-exit timeout.
  • Refactor

    • Centralized shutdown orchestration to streamline and standardize application termination.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add @types/pg for better type-safety
- Refactor shutdown process in main.ts to use async/await for app and database termination.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

Walkthrough

Replaced inline SIGINT/SIGTERM handlers with a centralized async gracefulShutdown(app, signal) utility; added export type App = typeof app in src/main.ts; introduced src/util/graceful-shutdown.ts with guarded shutdown and forced-exit timer; updated devDependencies in package.json.

Changes

Cohort / File(s) Summary
Dependency updates
package.json
Added devDependency @types/pg = ^8.15.6; bumped devDependency pino-pretty from ^13.1.2 to ^13.1.3.
Application entry / exports
src/main.ts
Replaced inline SIGINT/SIGTERM shutdown logic with calls to gracefulShutdown(app, signal); removed direct DB shutdown and process.exit calls; added export type App = typeof app;.
Graceful shutdown utility
src/util/graceful-shutdown.ts
New async gracefulShutdown(app: App, signal: NodeJS.Signals): Promise<void> that guards against concurrent shutdowns, logs signal receipt, starts a 10s forced-exit timer, awaits app.stop(), closes DB client, and exits with code 0 or 1 depending on success.

Sequence Diagram(s)

sequenceDiagram
    actor Process
    participant App
    participant DB as "DB Client"
    Note over Process: SIGINT / SIGTERM

    Process->>App: gracefulShutdown(app, signal)
    activate App
    App->>App: guard concurrent shutdowns
    App->>App: log signal received
    App->>Process: start 10s forced-exit timer
    App->>App: await app.stop()
    App->>DB: await DB.$client.end()
    alt success
        App->>Process: clear timer
        App->>Process: exit(0)
    else error
        App->>Process: clear timer
        App->>Process: log error
        App->>Process: exit(1)
    end
    deactivate App
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify app.stop() usage and ensure it resolves reliably.
  • Confirm DB client close call (e.g., db.$client.end()) is valid and accessible from the shutdown module.
  • Check for possible import circularities introduced by exporting App.
  • Validate the 10s forced-exit timeout is acceptable for existing shutdown tasks.

Poem

🐇
I heard the signal, soft and low,
I tuck my logs and tiptoe slow.
A timed hop out the burrow door,
Clean paws, closed sockets, then I snore. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: adding type definitions (@types/pg) and refactoring graceful shutdown handling with async/await patterns.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/graceful-shutdown

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5bde5e and a8b7028.

📒 Files selected for processing (1)
  • src/util/graceful-shutdown.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/util/graceful-shutdown.ts

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/main.ts (1)

59-70: Async shutdown is good; add error handling around stop/close

Awaiting app.stop() and db.$client.end() in the signal handlers is a solid improvement for graceful shutdown. The remaining gap is lack of error handling: if either rejects, you get a noisy/unclear failure and may not reach process.exit(0).

Consider wrapping both awaits in try/catch/finally so errors are logged and the process still terminates deterministically, e.g.:

-process.once('SIGINT', async () => {
-  log.info('SIGINT received, shutting down...');
-  await app.stop();
-  await db.$client.end();
-  process.exit(0);
-});
+process.once('SIGINT', async () => {
+  log.info('SIGINT received, shutting down...');
+  try {
+    await app.stop();
+    await db.$client.end();
+  } catch (error: unknown) {
+    log.error({ err: error }, 'Error during SIGINT shutdown');
+  } finally {
+    process.exit(0);
+  }
+});
 
-process.once('SIGTERM', async () => {
-  log.info('SIGTERM received, shutting down...');
-  await app.stop();
-  await db.$client.end();
-  process.exit(0);
-});
+process.once('SIGTERM', async () => {
+  log.info('SIGTERM received, shutting down...');
+  try {
+    await app.stop();
+    await db.$client.end();
+  } catch (error: unknown) {
+    log.error({ err: error }, 'Error during SIGTERM shutdown');
+  } finally {
+    process.exit(0);
+  }
+});

If you want to go further, you could also extract a shared shutdown helper to avoid repeating the same sequence for both signals. Please also re‑run Biome (bun run lint:fix) and existing tests after this change, as per coding guidelines.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f256237 and dd674e4.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • package.json (1 hunks)
  • src/main.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,js,jsx}: Strictly follow Biome linter rules and run bun run lint:fix to auto-fix issues
Use explicit imports instead of wildcard imports

Files:

  • src/main.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: TypeScript strict mode is enabled. Do not use any types unless absolutely necessary
Use src/common/config.ts for environment variables with Envalid. Do not use process.env directly
All new features must include unit/integration tests

Files:

  • src/main.ts
🧠 Learnings (1)
📚 Learning: 2025-11-27T13:14:34.764Z
Learnt from: CR
Repo: truehazker/elysia-boilerplate PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-27T13:14:34.764Z
Learning: Applies to src/**/*.{ts,tsx,js,jsx} : Strictly follow Biome linter rules and run `bun run lint:fix` to auto-fix issues

Applied to files:

  • package.json
🔇 Additional comments (1)
package.json (1)

36-42: Dev dependency updates align with existing stack

Adding @types/pg on top of the existing pg runtime dependency and bumping pino-pretty in a patch version both look correct and low‑risk; no changes needed on this file. Please just ensure the lockfile and CI (lint/tests) are rerun so tooling stays in sync.

- Improve error handling during shutdown in main.ts for SIGINT and SIGTERM signals.
- Update pino-pretty to version 13.1.3 and cookie to version 1.1.1 in bun.lock.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd674e4 and 42e77f1.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • src/main.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,js,jsx}: Strictly follow Biome linter rules and run bun run lint:fix to auto-fix issues
Use explicit imports instead of wildcard imports

Files:

  • src/main.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: TypeScript strict mode is enabled. Do not use any types unless absolutely necessary
Use src/common/config.ts for environment variables with Envalid. Do not use process.env directly
All new features must include unit/integration tests

Files:

  • src/main.ts
🧬 Code graph analysis (1)
src/main.ts (1)
src/common/logger.ts (1)
  • log (4-19)

- Replace inline shutdown logic for SIGINT and SIGTERM with a dedicated gracefulShutdown utility function.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/util/graceful-shutdown.ts (1)

1-26: Graceful shutdown logic looks solid; consider guarding against double invocation and tightening types.

The shutdown sequence (log → timeout → app.stop()db.$client.end() → clear timeout → exit) is clear and addresses the previous concerns about duplication, error handling, and hanging shutdowns. Using import type { App } avoids a runtime circular dependency with src/main.ts, which is appropriate here.

Two small, non-blocking improvements you might consider:

  1. Prevent concurrent shutdown attempts
    If the process receives both SIGINT and SIGTERM in quick succession, gracefulShutdown could be invoked twice. A simple module‑scoped guard avoids overlapping shutdowns:
-import { log } from 'src/common/logger';
-import db from 'src/db';
-import type { App } from 'src/main';
-
-export async function gracefulShutdown(
-  app: App,
-  signal: string,
-): Promise<void> {
+import { log } from 'src/common/logger';
+import db from 'src/db';
+import type { App } from 'src/main';
+
+let isShuttingDown = false;
+
+export async function gracefulShutdown(
+  app: App,
+  signal: NodeJS.Signals | string,
+): Promise<void> {
+  if (isShuttingDown) {
+    log.warn(`Shutdown already in progress, ignoring ${signal}`);
+    return;
+  }
+  isShuttingDown = true;
  1. Narrow the signal type
    Instead of signal: string, you can use NodeJS.Signals (or a union of the ones you actually use) for better type‑safety:
export async function gracefulShutdown(
  app: App,
  signal: NodeJS.Signals,
): Promise<void> {

Also, given the guideline that new behavior should be covered by tests, please ensure you have tests (unit or integration) that validate at least:

  • Successful shutdown (logs, app.stop and db.$client.end called, exit code 0).
  • Failing shutdown (error logged, exit code 1).
  • Timeout behavior when shutdown takes too long (exit code 1).

If those are already present elsewhere, just confirm; otherwise, I can help sketch a test approach using spies on process.exit, app.stop, and db.$client.end.

src/main.ts (1)

59-62: App type export and signal wiring look correct; optional micro‑refactor possible.

The export type App = typeof app; alias is a neat way to share the concrete app type with the shutdown utility without leaking Elysia’s generic type parameters everywhere, and the process.once handlers correctly delegate to gracefulShutdown with the running app instance.

If you want to remove the tiny bit of duplication and keep the signal list in one place, you could do:

-export type App = typeof app;
-
-process.once('SIGINT', () => gracefulShutdown(app, 'SIGINT'));
-process.once('SIGTERM', () => gracefulShutdown(app, 'SIGTERM'));
+export type App = typeof app;
+
+const handleSignal = (signal: NodeJS.Signals) => gracefulShutdown(app, signal);
+
+process.once('SIGINT', () => handleSignal('SIGINT'));
+process.once('SIGTERM', () => handleSignal('SIGTERM'));

Not required, but it centralizes the signal handling pattern slightly and plays well with future extension (e.g., adding other signals).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42e77f1 and f5bde5e.

📒 Files selected for processing (2)
  • src/main.ts (2 hunks)
  • src/util/graceful-shutdown.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,js,jsx}: Strictly follow Biome linter rules and run bun run lint:fix to auto-fix issues
Use explicit imports instead of wildcard imports

Files:

  • src/util/graceful-shutdown.ts
  • src/main.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: TypeScript strict mode is enabled. Do not use any types unless absolutely necessary
Use src/common/config.ts for environment variables with Envalid. Do not use process.env directly
All new features must include unit/integration tests

Files:

  • src/util/graceful-shutdown.ts
  • src/main.ts
🧬 Code graph analysis (2)
src/util/graceful-shutdown.ts (2)
src/main.ts (1)
  • App (59-59)
src/common/logger.ts (1)
  • log (4-19)
src/main.ts (1)
src/util/graceful-shutdown.ts (1)
  • gracefulShutdown (5-26)
🔇 Additional comments (1)
src/main.ts (1)

7-7: Good decoupling by importing centralized gracefulShutdown.

Importing gracefulShutdown here and moving the logic to src/util/graceful-shutdown.ts cleans up main.ts and addresses the earlier duplication and exit‑flow concerns from past reviews. This keeps main.ts focused on composition and wiring rather than lifecycle details.

@truehazker truehazker merged commit d1593f2 into develop Dec 1, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants