Repository: prometheus/client_python
Pull request #237 (2018-02-04 20:06:54)

Set default timeout of pushgateway actions to 30s
Explicitly passing `None` will still trigger the no timeout behaviour of the underlying Python http/socket modules.

This is motived by hitting an odd case in a k8s cluster job where some job pods were hung for 2 hours in the finally-post-metrics step after some cluster unhappiness that had since been resolved. However, I couldn't later reproduce the behaviour locally, as my machine at least does timeout the socket after a reasonable window regardless.

Even so, was worth adapting our application code to set a timeout, and having a sensible default in the client library here also seems reasonable.


Patch:
diff --git a/prometheus_client/exposition.py b/prometheus_client/exposition.py
index a271df1..a2ba8fb 100644
--- a/prometheus_client/exposition.py
+++ b/prometheus_client/exposition.py
@@ -30,6 +30,7 @@ CONTENT_TYPE_LATEST = str('text/plain; version=0.0.4; charset=utf-8')
 
 PYTHON26_OR_OLDER = sys.version_info < (2, 7)
 
+
 def make_wsgi_app(registry=core.REGISTRY):
     '''Create a WSGI app which serves the metrics from a registry.'''
     def prometheus_app(environ, start_response):
@@ -179,7 +180,9 @@ def basic_auth_handler(url, method, timeout, headers, data, username=None, passw
     return handle
 
 
-def push_to_gateway(gateway, job, registry, grouping_key=None, timeout=None, handler=default_handler):
+def push_to_gateway(
+        gateway, job, registry, grouping_key=None, timeout=30,
+        handler=default_handler):
     '''Push metrics to the given pushgateway.
 
     `gateway` the url for your push gateway. Either of the form
@@ -190,7 +193,7 @@ def push_to_gateway(gateway, job, registry, grouping_key=None, timeout=None, han
     `grouping_key` please see the pushgateway documentation for details.
                    Defaults to None
     `timeout` is how long push will attempt to connect before giving up.
-              Defaults to None
+              Defaults to 30s, can be set to None for no timeout.
     `handler` is an optional function which can be provided to perform
               requests to the 'gateway'.
               Defaults to None, in which case an http or https request
@@ -221,7 +224,9 @@ def push_to_gateway(gateway, job, registry, grouping_key=None, timeout=None, han
     _use_gateway('PUT', gateway, job, registry, grouping_key, timeout, handler)
 
 
-def pushadd_to_gateway(gateway, job, registry, grouping_key=None, timeout=None, handler=default_handler):
+def pushadd_to_gateway(
+        gateway, job, registry, grouping_key=None, timeout=30,
+        handler=default_handler):
     '''PushAdd metrics to the given pushgateway.
 
     `gateway` the url for your push gateway. Either of the form
@@ -232,7 +237,7 @@ def pushadd_to_gateway(gateway, job, registry, grouping_key=None, timeout=None,
     `grouping_key` please see the pushgateway documentation for details.
                    Defaults to None
     `timeout` is how long push will attempt to connect before giving up.
-              Defaults to None
+              Defaults to 30s, can be set to None for no timeout.
     `handler` is an optional function which can be provided to perform
               requests to the 'gateway'.
               Defaults to None, in which case an http or https request
@@ -245,7 +250,8 @@ def pushadd_to_gateway(gateway, job, registry, grouping_key=None, timeout=None,
     _use_gateway('POST', gateway, job, registry, grouping_key, timeout, handler)
 
 
-def delete_from_gateway(gateway, job, grouping_key=None, timeout=None, handler=default_handler):
+def delete_from_gateway(
+        gateway, job, grouping_key=None, timeout=30, handler=default_handler):
     '''Delete metrics from the given pushgateway.
 
     `gateway` the url for your push gateway. Either of the form
@@ -255,7 +261,7 @@ def delete_from_gateway(gateway, job, grouping_key=None, timeout=None, handler=d
     `grouping_key` please see the pushgateway documentation for details.
                    Defaults to None
     `timeout` is how long delete will attempt to connect before giving up.
-              Defaults to None
+              Defaults to 30s, can be set to None for no timeout.
     `handler` is an optional function which can be provided to perform
               requests to the 'gateway'.
               Defaults to None, in which case an http or https request


Test patch:
diff --git a/tests/test_exposition.py b/tests/test_exposition.py
index a4cc385..9953e0f 100644
--- a/tests/test_exposition.py
+++ b/tests/test_exposition.py
@@ -172,6 +172,8 @@ class TestPushGateway(unittest.TestCase):
     def test_push_with_handler(self):
         def my_test_handler(url, method, timeout, headers, data):
             headers.append(['X-Test-Header', 'foobar'])
+            # Handler should be passed sane default timeout
+            self.assertEqual(timeout, 30)
             return default_handler(url, method, timeout, headers, data)
         push_to_gateway(self.address, "my_job", self.registry, handler=my_test_handler)
         self.assertEqual(self.requests[0][0].command, 'PUT')