Skip to content

Commit

Permalink
Change to use RLock and set a timeout to prevent infinite deadlocks
Browse files Browse the repository at this point in the history
  • Loading branch information
phodge authored and jamielennox committed Aug 30, 2022
1 parent 6f639fe commit 3f317f6
Showing 1 changed file with 10 additions and 2 deletions.
12 changes: 10 additions & 2 deletions requests_mock/mocker.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@

_original_send = requests.Session.send

_send_lock = threading.Lock()
# NOTE(phodge): we need to use an RLock (reentrant lock) here because
# requests.Session.send() is reentrant. See further comments where we
# monkeypatch get_adapter()
_send_lock = threading.RLock()


def _is_bound_method(method):
Expand Down Expand Up @@ -134,7 +137,10 @@ def _fake_send(session, request, **kwargs):
# are multiple threads running - one thread could restore the
# original get_adapter() just as a second thread is about to
# execute _original_send() below
with _send_lock:
if not _send_lock.acquire(timeout=10):
raise Exception("Could not acquire threading lock - possible deadlock scenario")

try:
# mock get_adapter
_set_method(session, "get_adapter", _fake_get_adapter)

Expand All @@ -160,6 +166,8 @@ def _fake_send(session, request, **kwargs):
finally:
# restore get_adapter
_set_method(session, "get_adapter", self._last_get_adapter)
finally:
_send_lock.release()

# if we are here it means we must run the real http request
# Or, with nested mocks, to the parent mock, that is why we use
Expand Down

0 comments on commit 3f317f6

Please sign in to comment.