From 3f1a7ab10875dd3ce651d0dd9d1666e0ac1e096b Mon Sep 17 00:00:00 2001 From: Matt Bennett Date: Wed, 5 Apr 2017 17:52:45 +0100 Subject: [PATCH 1/5] add regression test --- setup.py | 1 + test_nameko_sentry.py | 51 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/setup.py b/setup.py index cae7b05..c97739f 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,7 @@ "flake8==2.5.0", "pylint==1.5.1", "pytest==2.8.3", + "objgraph==3.1.0" ] }, zip_safe=True, diff --git a/test_nameko_sentry.py b/test_nameko_sentry.py index 17c98a2..cc4a334 100644 --- a/test_nameko_sentry.py +++ b/test_nameko_sentry.py @@ -1,11 +1,14 @@ +import gc import json import logging import socket import eventlet +import objgraph import pytest from eventlet.event import Event from mock import ANY, Mock, patch, PropertyMock +from nameko.extensions import DependencyProvider from nameko.exceptions import RemoteError from nameko.rpc import rpc from nameko.standalone.rpc import ServiceRpcProxy @@ -883,6 +886,54 @@ def called_twice(worker_ctx, res, exc_info): assert expected_crumb_q2 not in breadcrumbs_map['q1'] +@pytest.mark.usefixtures('patched_sentry') +class TestReleaseMemory(object): + + @pytest.fixture + def log(self): + return logging.getLogger("test") + + @pytest.fixture + def service_cls(self, log): + + class Unsafe(DependencyProvider): + + def get_dependency(self, worker_ctx): + return worker_ctx.container._worker_threads[worker_ctx] + + class Service(object): + name = "service" + + sentry = SentryReporter() + unsafe = Unsafe() + + @rpc + def broken(self): + log.info("breadcrumb %s", self.unsafe) + raise CustomException("Error!") + + return Service + + def test_leak(self, container_factory, service_cls, config): + # regression test for + # https://github.com/mattbennett/nameko-sentry/issues/12 + + container = container_factory(service_cls, config) + container.start() + + count_before = objgraph.count('raven.breadcrumbs.BreadcrumbBuffer') + + with entrypoint_hook(container, 'broken') as hook: + for _ in range(5): + with pytest.raises(CustomException): + hook() + + gc.collect() + + count_after = objgraph.count('raven.breadcrumbs.BreadcrumbBuffer') + assert count_before == count_after == 1 + + class TestEndToEnd(object): @pytest.fixture From cce777e9102c0081ea0e919f07457aeaf1e36054 Mon Sep 17 00:00:00 2001 From: Matt Bennett Date: Wed, 5 Apr 2017 17:53:40 +0100 Subject: [PATCH 2/5] explicitly clear context on worker teardown --- nameko_sentry.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nameko_sentry.py b/nameko_sentry.py index f20e04a..6986112 100644 --- a/nameko_sentry.py +++ b/nameko_sentry.py @@ -146,6 +146,9 @@ def worker_result(self, worker_ctx, result, exc_info): self.capture_exception(worker_ctx, exc_info) + def worker_teardown(self, worker_ctx): + self.client.context.clear(deactivate=True) + def capture_exception(self, worker_ctx, exc_info): message = self.format_message(worker_ctx, exc_info) From f95759fac1681d42511891c011d9b925f976407f Mon Sep 17 00:00:00 2001 From: Matt Bennett Date: Wed, 5 Apr 2017 18:34:08 +0100 Subject: [PATCH 3/5] collect garbage from previous tests first --- test_nameko_sentry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_nameko_sentry.py b/test_nameko_sentry.py index cc4a334..2dbbe1d 100644 --- a/test_nameko_sentry.py +++ b/test_nameko_sentry.py @@ -921,6 +921,7 @@ def test_leak(self, container_factory, service_cls, config): container = container_factory(service_cls, config) container.start() + gc.collect() count_before = objgraph.count('raven.breadcrumbs.BreadcrumbBuffer') with entrypoint_hook(container, 'broken') as hook: @@ -929,7 +930,6 @@ def test_leak(self, container_factory, service_cls, config): hook() gc.collect() - count_after = objgraph.count('raven.breadcrumbs.BreadcrumbBuffer') assert count_before == count_after == 1 From 26a2e9c04a7fae860a3fa8bb56ce561b9c4c6c23 Mon Sep 17 00:00:00 2001 From: Matt Bennett Date: Wed, 5 Apr 2017 18:40:02 +0100 Subject: [PATCH 4/5] try sleeping before gc --- test_nameko_sentry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test_nameko_sentry.py b/test_nameko_sentry.py index 2dbbe1d..e21a073 100644 --- a/test_nameko_sentry.py +++ b/test_nameko_sentry.py @@ -929,6 +929,7 @@ def test_leak(self, container_factory, service_cls, config): with pytest.raises(CustomException): hook() + eventlet.sleep(.5) gc.collect() count_after = objgraph.count('raven.breadcrumbs.BreadcrumbBuffer') assert count_before == count_after == 1 From 58b493c8e09628806fe17db2687b8b8c8942db3c Mon Sep 17 00:00:00 2001 From: Matt Bennett Date: Wed, 5 Apr 2017 18:52:26 +0100 Subject: [PATCH 5/5] only need to check the counts are the same --- test_nameko_sentry.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test_nameko_sentry.py b/test_nameko_sentry.py index e21a073..ad023e9 100644 --- a/test_nameko_sentry.py +++ b/test_nameko_sentry.py @@ -929,10 +929,9 @@ def test_leak(self, container_factory, service_cls, config): with pytest.raises(CustomException): hook() - eventlet.sleep(.5) gc.collect() count_after = objgraph.count('raven.breadcrumbs.BreadcrumbBuffer') - assert count_before == count_after == 1 + assert count_before == count_after class TestEndToEnd(object):