Skip to content

Commit 3088bc1

Browse files
bloodearnestbrian-brazil
authored andcommitted
In multiprocess mode, ensure that metrics initialise to the correct (prometheus#328)
file. Without this, when forking, children can initialise metrics to the cached master pid file. This is racy, and can corrupt the master's mmaped file, breaking all subsequent collections. Signed-off-by: Simon Davy <simon.davy@canonical.com>
1 parent d737da7 commit 3088bc1

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

prometheus_client/core.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ class _MmapedValue(object):
666666
def __init__(self, typ, metric_name, name, labelnames, labelvalues, multiprocess_mode='', **kwargs):
667667
self._params = typ, metric_name, name, labelnames, labelvalues, multiprocess_mode
668668
with lock:
669+
self.__check_for_pid_change()
669670
self.__reset()
670671
values.append(self)
671672

tests/test_multiprocess.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,26 @@ def test_counter_across_forks(self):
141141
self.assertEqual(3, self.registry.get_sample_value('c_total'))
142142
self.assertEqual(1, c1._value.get())
143143

144+
def test_initialization_detects_pid_change(self):
145+
pid = 0
146+
core._ValueClass = core._MultiProcessValue(lambda: pid)
147+
148+
# can not inspect the files cache directly, as it's a closure, so we
149+
# check for the actual files themselves
150+
def files():
151+
fs = os.listdir(os.environ['prometheus_multiproc_dir'])
152+
fs.sort()
153+
return fs
154+
155+
c1 = Counter('c1', 'c1', registry=None)
156+
self.assertEqual(files(), ['counter_0.db'])
157+
c2 = Counter('c2', 'c2', registry=None)
158+
self.assertEqual(files(), ['counter_0.db'])
159+
pid = 1
160+
c3 = Counter('c3', 'c3', registry=None)
161+
self.assertEqual(files(), ['counter_0.db', 'counter_1.db'])
162+
163+
144164
@unittest.skipIf(sys.version_info < (2, 7), "Test requires Python 2.7+.")
145165
def test_collect(self):
146166
pid = 0

0 commit comments

Comments
 (0)