From efc0f0089e613ef3d2a2c9fb8242c69933dd3d06 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 25 Jun 2019 08:53:50 +0200 Subject: [PATCH] Allow ?no_track_activity=1 to opt-out of activity tracking (#4235) * Don't track API requests with `?no_track_activity=1` in the activity counter allows external idle-culling scripts to avoid updating the activity counter * Don't track kernel shutdown as kernel activity this causes idle-kernel shutdowns to restart the idle-shutdown timer user-requested shutdowns will still be tracked as api activity * test ?no_track_activity=1 tracking * Changelog for activity --- docs/source/changelog.rst | 10 ++++++++ notebook/base/handlers.py | 6 ++++- notebook/services/api/tests/test_api.py | 29 ++++++++++++++++------ notebook/services/kernels/kernelmanager.py | 1 - 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 51931f20c..daa7a858d 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -21,6 +21,16 @@ We strongly recommend that you upgrade pip to version 9+ of pip before upgrading Use ``pip install pip --upgrade`` to upgrade pip. Check pip version with ``pip --version``. +.. _release-6.0.0: + +6.0.0 +----- + +- add ``?no_track_activity=1`` argument to allow API requests + to not be registered as activity (e.g. API calls by external activity monitors). +- Kernels shutting down due to an idle timeout is no longer considered + an activity-updating event. + .. _release-5.7.8: 5.7.8 diff --git a/notebook/base/handlers.py b/notebook/base/handlers.py index cd801c9a1..31805ebde 100755 --- a/notebook/base/handlers.py +++ b/notebook/base/handlers.py @@ -650,7 +650,11 @@ class APIHandler(IPythonHandler): def update_api_activity(self): """Update last_activity of API requests""" # record activity of authenticated requests - if self._track_activity and getattr(self, '_user_cache', None): + if ( + self._track_activity + and getattr(self, '_user_cache', None) + and self.get_argument('no_track_activity', None) is None + ): self.settings['api_last_activity'] = utcnow() def finish(self, *args, **kwargs): diff --git a/notebook/services/api/tests/test_api.py b/notebook/services/api/tests/test_api.py index 0a48b793e..d09a06032 100644 --- a/notebook/services/api/tests/test_api.py +++ b/notebook/services/api/tests/test_api.py @@ -1,27 +1,27 @@ """Test the basic /api endpoints""" -import requests +from datetime import timedelta -from notebook._tz import isoformat +from notebook._tz import isoformat, utcnow from notebook.utils import url_path_join from notebook.tests.launchnotebook import NotebookTestBase -class KernelAPITest(NotebookTestBase): +class APITest(NotebookTestBase): """Test the kernels web service API""" - + def _req(self, verb, path, **kwargs): r = self.request(verb, url_path_join('api', path)) r.raise_for_status() return r - + def get(self, path, **kwargs): return self._req('GET', path) - + def test_get_spec(self): r = self.get('spec.yaml') assert r.text - + def test_get_status(self): r = self.get('status') data = r.json() @@ -30,3 +30,18 @@ class KernelAPITest(NotebookTestBase): assert data['last_activity'].endswith('Z') assert data['started'].endswith('Z') assert data['started'] == isoformat(self.notebook.web_app.settings['started']) + + def test_no_track_activity(self): + # initialize with old last api activity + old = utcnow() - timedelta(days=1) + settings = self.notebook.web_app.settings + settings['api_last_activity'] = old + # accessing status doesn't update activity + self.get('status') + assert settings['api_last_activity'] == old + # accessing with ?no_track_activity doesn't update activity + self.get('contents?no_track_activity=1') + assert settings['api_last_activity'] == old + # accessing without ?no_track_activity does update activity + self.get('contents') + assert settings['api_last_activity'] > old diff --git a/notebook/services/kernels/kernelmanager.py b/notebook/services/kernels/kernelmanager.py index b072e014b..53ae5d937 100644 --- a/notebook/services/kernels/kernelmanager.py +++ b/notebook/services/kernels/kernelmanager.py @@ -292,7 +292,6 @@ class MappingKernelManager(MultiKernelManager): kernel._activity_stream = None self.stop_buffering(kernel_id) self._kernel_connections.pop(kernel_id, None) - self.last_kernel_activity = utcnow() # Decrease the metric of number of kernels # running for the relevant kernel type by 1