Skip to content

Exception Handling When Failed To Send An Event #1290

@st0012

Description

@st0012

Introduction

This plan's goal is to propose a general guideline on how to handle exceptions that occur when the SDK is sending events to Sentry.

The goal is to make sure:

  • Applications won't be interrupted unnecessarily.
  • Users can know if the event is sent or not.

Related Issues

Below are the types of exceptions that could occur when sending an event to Sentry:

External Exceptions

An external exception is an error triggered by something outside of the SDK's control. For example:

  • Networking error
  • Redis connection error (fail to enqueue a background job)

These exceptions shouldn't interrupt the user's program. For example, failing to send a transaction to Sentry can't cause the response to return 500. This means:

  • these exceptions should be rescued whenever possible.
    • however, if these exceptions happen in a separated process, like a background job, they could fail for triggering a retry.
  • whatever happens needs to be written in the log.

User Exceptions

Because the SDK also invokes user-defined callbacks, like before_send, those callbacks could trigger arbitrary errors. For example:

  • Undefined method error

These exceptions should not be swallowed.

Exception Handling Principles

  • Any exception happens after Sentry.capture_* is called shouldn't crash the user's app.
  • Any exception happens in the background should be raised.

Exception Hotspots in Ruby SDK's Event Sending Flow

  • Client#capture_event <- should rescue and log all the errors
    • async block - could be either user or external exception
    • Client#send_event
      • before_send callback - user exception
      • HTTPTransport#send_data - external exception

As you can see, the flow can trigger either user or external exceptions, which makes handling them a bit tricky.

Exception Handling In Different Scenarios

Now, because Ruby SDK has different sync/async options, the situation gets even more complicated. Here's the breakdown for different scenarios:

Sending Events Inline (without async nor background worker)

  • Client#capture_event <- should rescue and log all the errors
    • Client#send_event
      • before_send callback - user exception
      • HTTPTransport#send_data - external exception

With Async

These happen inline

  • Client#capture_event <- should rescue and log all the errors
    • async block - could be either user or external exception

These happen in the worker

  • Client#send_event <- should raise both external and user exception
    • before_send callback - user exception
    • HTTPTransport#send_data - external exception

With Background Worker

These happen inline

  • Client#capture_event

These happen in the worker

  • Client#send_event <- should raise both external and user exception
    • before_send callback - user exception
    • HTTPTransport#send_data - external exception

Diagram

Sentry Ruby SDK Event Sending Flow

Metadata

Metadata

Assignees

No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions