Skip to content

Commit ae330f2

Browse files
Use requests.session instead of requests directly (#439)
requests.request() is not fork safe. When forking happens, thread pool might be in a bad state. Instead use session and stored within http_worker
1 parent 608e9dc commit ae330f2

28 files changed

+64
-63
lines changed

statsig/http_worker.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def __init__(
4545
self.__statsig_metadata = statsig_metadata
4646
self.__diagnostics = diagnostics
4747
self.__request_count = 0
48+
self.__request_session = requests.session()
4849

4950
def is_pull_worker(self) -> bool:
5051
return True
@@ -191,7 +192,7 @@ def _run_request_with_strict_timeout(self, method, url, headers, payload, timeou
191192
for_initialize=False, get_text_value_only=False) -> RequestResult:
192193
def request_task():
193194
try:
194-
with requests.request(method, url, data=payload, headers=headers, timeout=timeout,
195+
with self.__request_session.request(method, url, data=payload, headers=headers, timeout=timeout,
195196
stream=True) as response:
196197
try:
197198
response.raise_for_status()

tests/test_api_overrides.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ def mock_apis(*args, **kwargs):
3535
return stub.mock(*args, **kwargs)
3636

3737

38-
@patch('requests.request', side_effect=mock_apis)
38+
@patch('requests.Session.request', side_effect=mock_apis)
3939
class TestApiOverrides(unittest.TestCase):
4040
@classmethod
41-
@patch('requests.request', side_effect=mock_apis)
41+
@patch('requests.Session.request', side_effect=mock_apis)
4242
def setUpClass(cls, mock_request):
4343
cls.api_override = False
4444
cls.log_event_override = False

tests/test_background_sync.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def setUp(self):
1919
def tearDown(self):
2020
self._client.shutdown()
2121

22-
@patch('requests.request', side_effect=_network_stub.mock)
22+
@patch('requests.Session.request', side_effect=_network_stub.mock)
2323
def test_sync_cycle(self, mock_request):
2424
self.config_sync_count = 0
2525
self.idlist_sync_count = 0
@@ -315,7 +315,7 @@ def id_list_3_callback(url: str, **kwargs):
315315
self.assertEqual(self.idlist_2_download_count, 1)
316316
self.assertEqual(self.idlist_3_download_count, 1)
317317

318-
@patch('requests.request', side_effect=_network_stub.mock)
318+
@patch('requests.Session.request', side_effect=_network_stub.mock)
319319
def test_sync_cycle_no_idlist(self, mock_request):
320320
self.config_sync_count = 0
321321
self.idlist_sync_count = 0
@@ -361,7 +361,7 @@ def get_id_lists_callback(url: str, **kwargs):
361361
self.assertEqual(self.config_sync_count, 2)
362362
self.assertEqual(self.idlist_sync_count, 2)
363363

364-
@patch('requests.request', side_effect=_network_stub.mock)
364+
@patch('requests.Session.request', side_effect=_network_stub.mock)
365365
def test_dcs_retry(self, mock_request):
366366
self.config_sync_count = 0
367367
self.idlist_sync_count = 0
@@ -405,7 +405,7 @@ def download_config_specs_code_callback(url: str, **kwargs):
405405
time.sleep(1)
406406
self.assertEqual(self.config_sync_count, 2)
407407

408-
time.sleep(1)
408+
time.sleep(2)
409409
self.assertEqual(self.config_sync_count, 3)
410410

411411
self._client.shutdown()

tests/test_bg_thread_spawning.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class TestBackgroundThreadSpawning(unittest.TestCase):
1616
_event = StatsigEvent(_user, "an_event")
1717
_actions: List[Callable]
1818

19-
@patch('requests.request', side_effect=_network_stub.mock)
19+
@patch('requests.Session.request', side_effect=_network_stub.mock)
2020
def setUp(self, mock_request) -> None:
2121
server = StatsigServer()
2222
options = StatsigOptions(

tests/test_concurrency.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class TestStatsigConcurrency(unittest.TestCase):
2323
_event_count_lock = threading.Lock()
2424

2525
@classmethod
26-
@patch('requests.request', side_effect=_network_stub.mock)
26+
@patch('requests.Session.request', side_effect=_network_stub.mock)
2727
def setUpClass(cls, mock_request):
2828
cls._idlist_sync_count = 0
2929
cls._download_id_list_count = 0
@@ -83,7 +83,7 @@ def log_event_callback(url: str, **kwargs):
8383
def tearDownClass(cls) -> None:
8484
statsig.shutdown()
8585

86-
@patch('requests.request', side_effect=_network_stub.mock)
86+
@patch('requests.Session.request', side_effect=_network_stub.mock)
8787
def test_checking_and_updating_concurrently(self, mock_request):
8888
self.threads = []
8989
for x in range(10):

tests/test_concurrency_on_initialize.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ def _mock_thread_start(**kwargs):
1212
raise RuntimeError("Failed to start thread")
1313

1414

15-
@patch('requests.request', side_effect=_network_stub.mock)
15+
@patch('requests.Session.request', side_effect=_network_stub.mock)
1616
class TestConcurrencyOnInit(unittest.TestCase):
1717
_server: StatsigServer
1818
_user = StatsigUser(user_id="a-user")
1919

20-
@patch('requests.request', side_effect=_network_stub.mock)
20+
@patch('requests.Session.request', side_effect=_network_stub.mock)
2121
def setUp(self, mock_request) -> None:
2222
self._server = StatsigServer()
2323

tests/test_dcs_override_log_event_interval.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
class DCSOverrideTest(unittest.TestCase):
1515
_network_stub = NetworkStub("http://override-log-event-interval-test")
1616

17-
@patch('requests.request', side_effect=_network_stub.mock)
17+
@patch('requests.Session.request', side_effect=_network_stub.mock)
1818
def setUp(self, mock_request):
1919
self._instance = StatsigServer()
2020
options = StatsigOptions(
@@ -32,10 +32,10 @@ def setUp(self, mock_request):
3232
self._user = StatsigUser("dloomb")
3333
self.flush()
3434

35-
@patch('requests.request', side_effect=_network_stub.mock)
35+
@patch('requests.Session.request', side_effect=_network_stub.mock)
3636
def flush(self, mock_request):
3737
self._instance.flush()
3838

39-
@patch('requests.request', side_effect=_network_stub.mock)
39+
@patch('requests.Session.request', side_effect=_network_stub.mock)
4040
def test_interval_is_overridden(self, mock_request):
4141
self.assertEqual(self._instance._logger._logger_worker._log_interval, 100.0)

tests/test_diagnostics_core_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121

2222

2323
@patch("time.time", return_value=123)
24-
@patch("requests.request", side_effect=_network_stub.mock)
24+
@patch("requests.Session.request", side_effect=_network_stub.mock)
2525
class TestDiagnosticsCoreAPI(unittest.TestCase):
2626
_server: StatsigServer
2727
_evaluator: _Evaluator
2828
_user = StatsigUser(user_id="a-user")
2929

30-
@patch("requests.request", side_effect=_network_stub.mock)
30+
@patch("requests.Session.request", side_effect=_network_stub.mock)
3131
def setUp(self, mock_request) -> None:
3232
response = json.loads(CONFIG_SPECS_RESPONSE)
3333
response["diagnostics"] = {

tests/test_eval_callback.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
_network_stub = NetworkStub("http://test-statsig-e2e")
1717

1818

19-
@patch('requests.request', side_effect=_network_stub.mock)
19+
@patch('requests.Session.request', side_effect=_network_stub.mock)
2020
class TestEvalCallback(unittest.TestCase):
2121
_logs = {}
2222
_gateName = ""
@@ -25,7 +25,7 @@ class TestEvalCallback(unittest.TestCase):
2525
_spec_match = False
2626

2727
@classmethod
28-
@patch('requests.request', side_effect=_network_stub.mock)
28+
@patch('requests.Session.request', side_effect=_network_stub.mock)
2929
def setUpClass(cls, mock_request):
3030
_network_stub.stub_request_with_value(
3131
"download_config_specs/.*", 200, json.loads(CONFIG_SPECS_RESPONSE))

tests/test_evaluation_details.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515

1616

1717
@patch('time.time', return_value=123)
18-
@patch('requests.request', side_effect=_network_stub.mock)
18+
@patch('requests.Session.request', side_effect=_network_stub.mock)
1919
class TestEvaluationDetails(unittest.TestCase):
2020
_server: StatsigServer
2121
_evaluator: _Evaluator
2222
_user = StatsigUser(user_id="a-user")
2323

24-
@patch('requests.request', side_effect=_network_stub.mock)
24+
@patch('requests.Session.request', side_effect=_network_stub.mock)
2525
def setUp(self, mock_request) -> None:
2626
server = StatsigServer()
2727
self.options = StatsigOptions(

0 commit comments

Comments
 (0)