From 931e06eec5160ceafda3aeb58c6a7f9a7870adda Mon Sep 17 00:00:00 2001 From: Huw Jones Date: Tue, 18 Jun 2024 13:43:33 +0100 Subject: [PATCH 1/2] collector/BaseCollector/get_all: add test for dict modification For https://github.com/claws/aioprometheus/issues/85 --- tests/test_metrics.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 8d85a97..b9a216e 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -1,4 +1,5 @@ import unittest +from threading import Thread from aioprometheus.collectors import ( REGISTRY, @@ -166,6 +167,31 @@ def country_fetcher(x): sorted_result = sorted(c.get_all(), key=country_fetcher) self.assertEqual(sorted_data, sorted_result) + def test_get_all_change_iter(self) -> None: + """ + test iterating over get_all when the underlying dict changes + + For https://github.com/claws/aioprometheus/issues/85 + """ + c = Collector(**self.default_data) + + # Create a large collection of values to increase the chance of a race + for i in range(100000): + c.set_value({f"b-{i}": "a"}, i) + + # Now create a thread that will add a huge amount more values + def set_more_values(): + for j in range(10000): + c.set_value({f"a-{j}": "a"}, j) + + t = Thread(daemon=True, target=set_more_values) + t.start() + + # Hope that due to the large amount of labels involved, we will smack + # head-first into the race of iterating over the dict whilst adding more + # unique labels to it. + list(c.get_all()) + class TestCounterMetric(unittest.TestCase): def setUp(self): From 7a7ae414071c7b75e93a1d7c7086293e48d81d56 Mon Sep 17 00:00:00 2001 From: Huw Jones Date: Tue, 18 Jun 2024 13:43:56 +0100 Subject: [PATCH 2/2] collector/BaseCollector/get_all: prevent iteration over modified dict Fixes https://github.com/claws/aioprometheus/issues/85 --- src/aioprometheus/collectors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aioprometheus/collectors.py b/src/aioprometheus/collectors.py index fb8c3d4..d3d24d3 100644 --- a/src/aioprometheus/collectors.py +++ b/src/aioprometheus/collectors.py @@ -161,7 +161,7 @@ def get_all(self) -> List[Tuple[LabelsType, NumericValueType]]: itself. """ result = [] - for k in self.values: + for k in list(self.values): # Check if is a single value dict (custom empty key) key = ( {}