Skip to content

Calling Sentry.flush() with @sentry/node always throws an exception on Next.js API endpoints #3748

@Vadorequest

Description

@Vadorequest

Package + Version

  • @sentry/browser 6.3.6
  • @sentry/node 6.3.6
  • raven-js
  • raven-node (raven for node)
  • other:

Version:

0.0.0

Description

It's recommended by Next.js to call Sentry.flush() manually, before returning an HTTP response from API endpoints.

But, it doesn't work so well. When calling the API endpoint, it doesn't send the error to Sentry and fails with [flushSafe] An exception was thrown while running Sentry.flush(). (see implementation below)

The timeout being used is 5000, which is more than what's recommended (2000).

What's also weird is that I wasn't flushing before and it was working (at least sometimes) but now it always fails.

2021-06-24T20:33:32.151Z [modules/core/amplitude/amplitudeServerClient] Logging Amplitude event "api-invoked" with properties: { apiEndpoint: 'error' }
2021-06-24T20:33:52.953Z	3751ccb9-311e-4e5d-87b1-6b1a1aa04ce9	ERROR	2021-06-24T20:33:52.397Z [api/error] Fake error - Sentry test from /api/error
2021-06-24T20:33:52.953Z	3751ccb9-311e-4e5d-87b1-6b1a1aa04ce9	ERROR	2021-06-24T20:33:35.287Z [modules/core/sentry/universal] [flushSafe] An exception was thrown while running Sentry.flush() false
import { logEvent } from '@/modules/core/amplitude/amplitudeServerClient';
import {
  AMPLITUDE_API_ENDPOINTS,
  AMPLITUDE_EVENTS,
} from '@/modules/core/amplitude/events';
import { createLogger } from '@/modules/core/logging/logger';
import { configureReq } from '@/modules/core/sentry/server';
import { flushSafe } from '@/modules/core/sentry/universal';
import * as Sentry from '@sentry/node';
import {
  NextApiRequest,
  NextApiResponse,
} from 'next';

const fileLabel = 'api/error';
const logger = createLogger({
  fileLabel,
});

/**
 * Error endpoint - Throws an error upon being called.
 *
 * Mock API endpoint whose sole purpose is to throw an error, nothing else.
 * Meant to be used to check whether monitoring (Sentry) works as expected.
 *
 * @param req
 * @param res
 * @method GET
 */
export const error = async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {
  try {
    configureReq(req, { fileLabel });

    await logEvent(AMPLITUDE_EVENTS.API_INVOKED, null, {
      apiEndpoint: AMPLITUDE_API_ENDPOINTS.ERROR,
    });

    throw Error('Fake error - Sentry test from /api/error');
  } catch (e) {
    Sentry.captureException(e);
    logger.error(e.message);

    await flushSafe();

    res.json({
      error: true,
      message: process.env.NEXT_PUBLIC_APP_STAGE === 'production' ? undefined : e.message,
    });
  }
};

/**
 * Flushes Sentry queue in a safe way.
 *
 * It's necessary to flush all Sentry events on the server, because Vercel runs on AWS Lambda, see https://vercel.com/docs/platform/limits#streaming-responses
 * If you don't flush, then it's possible the Sentry events won't be sent.
 * This helper is meant to be used for backend-only usage. (not frontend)
 *
 * There is a potential bug in Sentry that throws an exception when flushing times out, causing API endpoints to fail.
 * @see https://github.com/getsentry/sentry/issues/26870
 */
export const flushSafe = async (): Promise<boolean> => {
  try {
    return await Sentry.flush(FLUSH_TIMEOUT);
  } catch (e) {
    logger.error(`[flushSafe] An exception was thrown while running Sentry.flush()`, e);
    return false;
  }
};

export default error;

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    Package: nextjsIssues related to the Sentry Nextjs SDK

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions