Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis pull request adds exception handling to health check plugins across four plugin variants (common, sync, public, and startup). Previously, if a health check's checker function threw an exception, it would crash the request or application startup. The changes now wrap each checker invocation in a try/catch block, converting any thrown exceptions into a consistent failure state. Non-Error values are coerced to Error instances, and all results are normalized into an Either format for consistent downstream processing. Tests are added to verify that thrown exceptions result in failed health checks while allowing the application to continue operating. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
lib/plugins/healthcheck/startupHealthcheckPlugin.ts (1)
8-17: Consider extracting sharedexecuteHealthCheckhelper.The same try/catch +
isErrorpattern is duplicated inline incommonHealthcheckPlugin.ts(lines 100-105) andpublicHealthcheckPlugin.ts(lines 51-55). This helper could be moved tohealthcheckCommons.tsand reused across all async healthcheck plugins to reduce duplication.♻️ Potential shared helper in healthcheckCommons.ts
// In healthcheckCommons.ts import { type Either, isError } from '@lokalise/node-core' import type { AnyFastifyInstance } from '../pluginsCommon.js' export async function executeHealthCheck( checker: HealthChecker, app: AnyFastifyInstance, ): Promise<Either<Error, true>> { try { return await checker(app) } catch (err) { return { error: isError(err) ? err : new Error(String(err)) } } }Also applies to: 34-34
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/plugins/healthcheck/startupHealthcheckPlugin.ts` around lines 8 - 17, Extract the duplicated try/catch + isError pattern into a shared helper named executeHealthCheck placed in healthcheckCommons.ts and reuse it from commonHealthcheckPlugin.ts and publicHealthcheckPlugin.ts; specifically, create executeHealthCheck(checker: HealthChecker, app: AnyFastifyInstance): Promise<Either<Error, true>> that wraps await checker(app) and on throw returns { error: isError(err) ? err : new Error(String(err)) }, then import and call this helper from the existing locations (replace the inline logic in commonHealthcheckPlugin.ts and publicHealthcheckPlugin.ts with calls to executeHealthCheck).lib/plugins/healthcheck/commonHealthcheckPlugin.spec.ts (1)
324-351: Good test coverage for exception handling.The test correctly validates that a throwing optional checker results in
PARTIALLY_HEALTHYstatus. Consider adding a complementary test case where a mandatory checker throws to verify it returns500withFAILheartbeat, ensuring both paths are covered.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/plugins/healthcheck/commonHealthcheckPlugin.spec.ts` around lines 324 - 351, Add a complementary test that verifies a throwing mandatory checker causes a 500 response and FAIL heartbeat: call initApp with healthChecks including a checker that throws (use throwingHealthcheckChecker) and set isMandatory: true for that check, then perform the GET on PRIVATE_ENDPOINT and assert response.statusCode is 500 and response.json() contains heartbeat 'FAIL' and the failing check set to 'FAIL'; place the test alongside the existing 'handles checker that throws an error as a failed healthcheck' spec so it covers the mandatory-error path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@lib/plugins/healthcheck/commonHealthcheckPlugin.spec.ts`:
- Around line 324-351: Add a complementary test that verifies a throwing
mandatory checker causes a 500 response and FAIL heartbeat: call initApp with
healthChecks including a checker that throws (use throwingHealthcheckChecker)
and set isMandatory: true for that check, then perform the GET on
PRIVATE_ENDPOINT and assert response.statusCode is 500 and response.json()
contains heartbeat 'FAIL' and the failing check set to 'FAIL'; place the test
alongside the existing 'handles checker that throws an error as a failed
healthcheck' spec so it covers the mandatory-error path.
In `@lib/plugins/healthcheck/startupHealthcheckPlugin.ts`:
- Around line 8-17: Extract the duplicated try/catch + isError pattern into a
shared helper named executeHealthCheck placed in healthcheckCommons.ts and reuse
it from commonHealthcheckPlugin.ts and publicHealthcheckPlugin.ts; specifically,
create executeHealthCheck(checker: HealthChecker, app: AnyFastifyInstance):
Promise<Either<Error, true>> that wraps await checker(app) and on throw returns
{ error: isError(err) ? err : new Error(String(err)) }, then import and call
this helper from the existing locations (replace the inline logic in
commonHealthcheckPlugin.ts and publicHealthcheckPlugin.ts with calls to
executeHealthCheck).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: lokalise/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b0f9ef45-7128-4e01-9d8c-37f348db2dab
📒 Files selected for processing (8)
lib/plugins/healthcheck/commonHealthcheckPlugin.spec.tslib/plugins/healthcheck/commonHealthcheckPlugin.tslib/plugins/healthcheck/commonSyncHealthcheckPlugin.spec.tslib/plugins/healthcheck/commonSyncHealthcheckPlugin.tslib/plugins/healthcheck/publicHealthcheckPlugin.spec.tslib/plugins/healthcheck/publicHealthcheckPlugin.tslib/plugins/healthcheck/startupHealthcheckPlugin.spec.tslib/plugins/healthcheck/startupHealthcheckPlugin.ts
Changes
Do not produce unhandler errors when checker fails
Checklist
major,minor,patchorskip-release