* fix(jobs): survive Redis Cloud maintenance reconnects BullMQ duplicates ioredis connections without inheriting error listeners, so Redis Cloud maintenance (ECONNABORTED) crashed the API process. Attach error handlers on duplicates, harden reconnect options for failover, and add API process-level safety nets. Co-authored-by: Rotimi Best <[email protected]> * refactor(jobs): address review feedback on Redis resilience fix - reconnectOnError returns 2 for READONLY/LOADING so the failed command is resent against the newly promoted primary after failover - export prepareRedisConnection and test the real implementation instead of a reimplemented copy; add a no-double-listener regression case - API uncaughtException now reports to Sentry and fails fast (flush + exit 1) so the orchestrator restarts cleanly instead of running in an undefined state Co-authored-by: Rotimi Best <[email protected]> * fix(api): don't fail-fast on transient Redis errors in process guard End-to-end testing (restarting Redis to simulate Cloud maintenance) revealed node-redis surfaces reconnect failures as an uncaught AggregateError [ECONNREFUSED], which the fail-fast uncaughtException guard turned into a process exit. Classify transient Redis/socket errors (incl. AggregateError sub-errors) and log-and-continue for those; still fail fast on unknown errors. Co-authored-by: Rotimi Best <[email protected]> * fix(api): address PR review on Redis process guards and logging - Fail fast on non-transient unhandledRejection (Greptile) - Filter Sentry OnUncaughtException/OnUnhandledRejection integrations to avoid double-capture; keep custom guards with transient Redis filtering - Make wrapDuplicate idempotent; throttle reconnect/error logs during maintenance - Drop READONLY/LOADING from node-redis transient classifier (command-level only) Co-authored-by: Rotimi Best <[email protected]> * fix(api): rate-limit transient Redis warnings in process guards Reuse logTransientRedisEvent from core so maintenance bursts do not flood logs from uncaughtException/unhandledRejection handlers. Co-authored-by: Rotimi Best <[email protected]> --------- Co-authored-by: Cursor Agent <[email protected]> Co-authored-by: Rotimi Best <[email protected]>
28 lines
1014 B
TypeScript
28 lines
1014 B
TypeScript
/**
|
|
* Must be imported as the FIRST thing in `apps/api/src/index.ts`. The Sentry
|
|
* Node SDK relies on auto-instrumentation that hooks into Node's `require`
|
|
* resolution and module loaders; any code that runs before this file initializes
|
|
* Sentry will not be traced.
|
|
*/
|
|
import * as Sentry from '@sentry/node';
|
|
|
|
const dsn = process.env.SENTRY_DSN?.trim();
|
|
const isProd = process.env.NODE_ENV === 'production';
|
|
const isSelfHosted = process.env.PUBLIC_IS_SELFHOSTED === 'true';
|
|
|
|
if (dsn && isProd && !isSelfHosted) {
|
|
Sentry.init({
|
|
dsn,
|
|
environment: process.env.SENTRY_ENVIRONMENT?.trim() || 'production',
|
|
tracesSampleRate: Number(process.env.SENTRY_TRACES_SAMPLE_RATE ?? 0),
|
|
sendDefaultPii: false,
|
|
// process-error-guards.ts registers handlers with transient Redis filtering.
|
|
integrations(integrations) {
|
|
return integrations.filter(
|
|
(integration) =>
|
|
integration.name !== 'OnUncaughtException' && integration.name !== 'OnUnhandledRejection'
|
|
);
|
|
}
|
|
});
|
|
}
|