Skip to content

Commit 7f25a39

Browse files
authored
feat: register atexit handler (#15)
* feat: register atexit handler * chore: add tests, stylefixes * fix: tests under py3
1 parent a0fd47b commit 7f25a39

File tree

3 files changed

+59
-18
lines changed

3 files changed

+59
-18
lines changed

sentry_sdk/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import uuid
33
import random
4+
import atexit
45

56
from .utils import Dsn, SkipEvent, ContextVar
67
from .transport import Transport
@@ -52,6 +53,8 @@ def __init__(self, dsn=None, *args, **kwargs):
5253
for integration in integrations:
5354
integration(self)
5455

56+
atexit.register(self.close)
57+
5558
@property
5659
def dsn(self):
5760
"""The DSN that created this event."""

sentry_sdk/transport.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
from __future__ import print_function
2+
13
import json
2-
import time
34
import zlib
45
import urllib3
56
import logging
67
import threading
78
import certifi
9+
import sys
10+
import traceback
11+
812
from datetime import datetime, timedelta
913

1014
from ._compat import queue
@@ -64,22 +68,23 @@ def thread():
6468
disabled_until = None
6569
while 1:
6670
item = transport._queue.get()
71+
if item is _SHUTDOWN:
72+
transport._queue.task_done()
73+
break
74+
6775
if disabled_until is not None:
68-
if disabled_until < datetime.utcnow():
76+
if datetime.utcnow() < disabled_until:
77+
transport._queue.task_done()
6978
continue
7079
disabled_until = None
7180

72-
if item is None:
73-
if transport._done:
74-
break
75-
continue
76-
elif item is _SHUTDOWN:
77-
break
78-
7981
try:
8082
disabled_until = send_event(transport._pool, item, auth)
83+
transport._queue.task_done()
8184
except Exception:
82-
logger.exception("Could not send sentry event")
85+
print("Could not send sentry event", file=sys.stderr)
86+
print(traceback.format_exc(), file=sys.stderr)
87+
transport._queue.task_done()
8388
continue
8489

8590
t = threading.Thread(target=thread)
@@ -91,7 +96,6 @@ class Transport(object):
9196
def __init__(self, dsn, http_proxy=None, https_proxy=None):
9297
self.dsn = dsn
9398
self._queue = None
94-
self._done = False
9599
self._pool = _make_pool(dsn, http_proxy=http_proxy, https_proxy=https_proxy)
96100

97101
def start(self):
@@ -108,7 +112,6 @@ def capture_event(self, event):
108112
pass
109113

110114
def close(self):
111-
self._done = True
112115
if self._queue is not None:
113116
try:
114117
self._queue.put_nowait(_SHUTDOWN)
@@ -117,12 +120,12 @@ def close(self):
117120
self._queue = None
118121

119122
def drain_events(self, timeout):
120-
deadline = time.time() + timeout
121123
q = self._queue
122-
while not self._done and q.qsize() > 0:
123-
if time.time() >= deadline:
124-
return False
125-
time.sleep(0.1)
124+
if q is None:
125+
return True
126+
127+
with q.all_tasks_done:
128+
q.all_tasks_done.wait(timeout)
126129
return True
127130

128131
def __del__(self):

tests/test_client.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import time
12
import pytest
3+
import sys
4+
import subprocess
5+
from textwrap import dedent
26
from sentry_sdk import Client
3-
from sentry_sdk.utils import Event, Dsn
47
from sentry_sdk.transport import Transport
8+
from sentry_sdk.utils import Event, Dsn
59

610

711
def test_transport_option(monkeypatch):
@@ -42,3 +46,34 @@ def capture_event(self, event):
4246
c.capture_event(e(Exception))
4347
c.capture_event(e(ValueError))
4448
pytest.raises(EventCaptured, lambda: c.capture_event(e(BaseException)))
49+
50+
51+
@pytest.mark.parametrize("num_messages", [10, 20])
52+
def test_atexit(tmpdir, monkeypatch, num_messages):
53+
app = tmpdir.join("app.py")
54+
app.write(
55+
dedent(
56+
"""
57+
import time
58+
from sentry_sdk import init, transport, capture_message
59+
60+
def send_event(pool, event, auth):
61+
time.sleep(0.1)
62+
print(event["message"])
63+
64+
transport.send_event = send_event
65+
init("http://foobar@localhost/123", drain_timeout={num_messages})
66+
67+
for _ in range({num_messages}):
68+
capture_message("HI")
69+
""".format(
70+
num_messages=num_messages
71+
)
72+
)
73+
)
74+
75+
start = time.time()
76+
output = subprocess.check_output([sys.executable, str(app)])
77+
end = time.time()
78+
assert int(end - start) == num_messages / 10
79+
assert output.count(b"HI") == num_messages

0 commit comments

Comments
 (0)