Skip to content

Flushing with timeout doesn't timeout and eventually crashes  #3806

Closed

Description

@Vadorequest

Package + Version

  • @sentry/nextjs 6.9.0

Description

Using this code in a Next.js API:

import {captureException, flush, withSentry} from '@sentry/nextjs';

const handler = async () => {
  try {
    throw new Error(
      'This is a fake error meant to help testing Sentry error reporting (monitoring).'
    );
  } catch (e) {
    captureException(e);

    await flush(5000); // Need to flush on API to send errors properly (issue in @sentry/nextjs)
  }
};

export default withSentry(handler);

Calling the API endpoint runs until the Serverless function times out.
Providing a value to flush() doesn't seem to be effective.

image

Activity

  1. Vadorequest commented on Jul 14, 2021

    @Vadorequest
    Author

    Also note I had to manually flush because if I don't, no error gets logged...

  2. Vadorequest commented on Jul 14, 2021

    @Vadorequest
    Author

    I had forgotten to run res.end() at the end, that was the cause of the infinite loading.

    But, the events don't show in Sentry nevertheless.

  3. kamilogorek commented on Jul 15, 2021

    @kamilogorek
    Contributor

    @lobsterkatie this is 99% the issue that you already found here -

    function wrapEndMethod(origEnd: ResponseEndMethod): WrappedResponseEndMethod {
    return async function newEnd(this: ScopedResponse, ...args: any[]) {
    // if the handler errored, it will have popped us out of the domain, so push the domain's scope onto the stack
    // just in case (if we *are* still in the domain, this will replace the current scope with a clone of itself,
    // which is effectively a no-op as long as we remember to pop it off when we're done)
    const currentHub = getCurrentHub();
    currentHub.pushScope(this.__sentryScope);
    const transaction = getActiveTransaction();
    console.log('Active transaction:', transaction?.name);
    if (transaction) {
    transaction.setHttpStatus(this.statusCode);
    // Push `transaction.finish` to the next event loop so open spans have a better chance of finishing before the
    // transaction closes, and make sure to wait until that's done before flushing events
    const transactionFinished: Promise<void> = new Promise(resolve => {
    setImmediate(() => {
    transaction.finish();
    resolve();
    });
    });
    await transactionFinished;
    }
    // flush the event queue to ensure that events get sent to Sentry before the response is finished and the lambda
    // ends
    try {
    logger.log('Flushing events...');
    await flush(2000);
    } catch (e) {
    logger.log(`Error while flushing events:\n${e}`);
    } finally {
    logger.log('Done flushing events');
    }
    // now that our work is done, we can pop off the scope and allow the response to end
    currentHub.popScope();
    return origEnd.call(this, ...args);
    };
    }

  4. lobsterkatie commented on Jul 19, 2021

    @lobsterkatie
    Member

    Yup - that's exactly it. There are still a few things in flux with that PR, but it should merge this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions