8000 Avoid re-entrant calls to GC collector's callback (#343) · Global-localhost/client_python@33bc65b · GitHub
[go: up one dir, main page]

Skip to content

Commit 33bc65b

Browse files
akxbrian-brazil
authored andcommitted
Avoid re-entrant calls to GC collector's callback (prometheus#343)
It looks like the Python GC engine can call the GC callback while it's still being called (likely if the callback does significant enough work), which may, if you're unlucky enough, lead into a stack overflow Python is unable to recover from. This patch should fix it, though no empirical tests have been made. Signed-off-by: Aarni Koskela <akx@iki.fi>
1 parent a50f3e4 commit 33bc65b

File tree

1 file changed

+25
-12
lines changed

1 file changed

+25
-12
lines changed

prometheus_client/gc_collector.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,32 @@ def __init__(self, registry=core.REGISTRY, gc=gc):
4747

4848
times = {}
4949

50+
# Avoid _cb() being called re-entrantly
51+
# by setting this flag and clearing it once
52+
# the callback operation is complete.
53+
# See https://github.com/prometheus/client_python/issues/322#issuecomment-438021132
54+
self.gc_cb_active = False
55+
5056
def _cb(phase, info):
51-
gen = info['generation']
52-
53-
if phase == 'start':
54-
times[gen] = time.time()
55-
56-
if phase == 'stop':
57-
delta = time.time() - times[gen]
58-
latency.labels(gen).observe(delta)
59-
if 'collected' in info:
60-
collected.labels(gen).observe(info['collected'])
61-
if 'uncollectable' in info:
62-
uncollectable.labels(gen).observe(info['uncollectable'])
57+
try:
58+
if self.gc_cb_active:
59+
return
60+
self.gc_cb_active = True
61+
62+
gen = info['generation']
63+
64+
if phase == 'start':
65+
times[gen] = time.time()
66+
67+
if phase == 'stop':
68+
delta = time.time() - times[gen]
69+
latency.labels(gen).observe(delta)
70+
if 'collected' in info:
71+
collected.labels(gen).observe(info['collected'])
72+
if 'uncollectable' in info:
73+
uncollectable.labels(gen).observe(info['uncollectable'])
74+
finally:
75+
self.gc_cb_active = False
6376

6477
gc.callbacks.append(_cb)
6578

0 commit comments

Comments
 (0)
0