How do you use Sentry?
Sentry Saas (sentry.io)
Version
2.71.0 (same on 2.48.0)
Steps to Reproduce
import sentry_sdk
from sentry_sdk.crons import capture_checkin
from sentry_sdk.transport import Transport
# 1. no active client
print(sentry_sdk.capture_event({"message": "x"})) # None
print(capture_checkin(monitor_slug="nightly", status="in_progress")) # '19fe1f76b846410381dd7937594d1ceb'
# 2. check-in dropped by before_send
sent = []
class RecordingTransport(Transport):
def capture_envelope(self, envelope):
sent.append(envelope)
sentry_sdk.init(dsn="https://[email protected]/1", transport=RecordingTransport,
before_send=lambda event, hint: None)
print(capture_checkin(monitor_slug="nightly", status="in_progress")) # '396229524fde41ce9cf4755cae73da0c'
sentry_sdk.flush()
print(len(sent)) # 0
Expected Result
The caller can tell that the check-in didn't go out, the same way capture_event returns None when the event is dropped. For example, capture_checkin returns None in that case.
Actual Result
capture_checkin ignores the return value of capture_event and always returns the generated (or passed-in) check_in_id.
This matters when the check-in is opened in one process and closed in another. We run scheduled Dramatiq jobs: the scheduler opens the in_progress check-in and passes the id to the worker in the message, and the worker opens its own check-in only when no id arrives. When the scheduler has no active client, the worker still gets an id, skips opening its own, and closes a check-in that never reached Sentry. We now check sentry_sdk.get_client().is_active() before calling capture_checkin, but that doesn't cover a check-in dropped in before_send. The Celery Beat integration hands the id over the same way (sentry-monitor-check-in-id).
A possible change: return None from capture_checkin when capture_event returns None, so the return type becomes Optional[str]. monitor and the Celery Beat integration keep working, because capture_checkin(check_in_id=None) generates a fresh id. One existing test would change: test_capture_checkin_sdk_not_initialized asserts that the passed-in id comes back when the SDK is not initialized. I have this change with tests ready locally (tests/test_crons.py and the Celery Beat crons tests pass, mypy is clean) and can open a PR if the approach is OK with you.
How do you use Sentry?
Sentry Saas (sentry.io)
Version
2.71.0 (same on 2.48.0)
Steps to Reproduce
Expected Result
The caller can tell that the check-in didn't go out, the same way
capture_eventreturnsNonewhen the event is dropped. For example,capture_checkinreturnsNonein that case.Actual Result
capture_checkinignores the return value ofcapture_eventand always returns the generated (or passed-in)check_in_id.This matters when the check-in is opened in one process and closed in another. We run scheduled Dramatiq jobs: the scheduler opens the
in_progresscheck-in and passes the id to the worker in the message, and the worker opens its own check-in only when no id arrives. When the scheduler has no active client, the worker still gets an id, skips opening its own, and closes a check-in that never reached Sentry. We now checksentry_sdk.get_client().is_active()before callingcapture_checkin, but that doesn't cover a check-in dropped inbefore_send. The Celery Beat integration hands the id over the same way (sentry-monitor-check-in-id).A possible change: return
Nonefromcapture_checkinwhencapture_eventreturnsNone, so the return type becomesOptional[str].monitorand the Celery Beat integration keep working, becausecapture_checkin(check_in_id=None)generates a fresh id. One existing test would change:test_capture_checkin_sdk_not_initializedasserts that the passed-in id comes back when the SDK is not initialized. I have this change with tests ready locally (tests/test_crons.pyand the Celery Beat crons tests pass, mypy is clean) and can open a PR if the approach is OK with you.