|
57 | 57 | HI_RES_STRATEGY = 'hi_res' |
58 | 58 | MAX_PAGE_LENGTH = 4000 |
59 | 59 |
|
60 | | -def _run_coroutines_in_separate_thread( |
61 | | - coroutines_task: Coroutine[Any, Any, list[tuple[Any, httpx.Response]]] |
62 | | -) -> list[httpx.Response]: |
| 60 | +def _get_asyncio_loop() -> asyncio.AbstractEventLoop: |
63 | 61 | if sys.version_info < (3, 10): |
64 | 62 | loop = asyncio.get_event_loop() |
65 | 63 | else: |
66 | 64 | try: |
67 | 65 | loop = asyncio.get_running_loop() |
68 | 66 | except RuntimeError: |
69 | 67 | loop = asyncio.new_event_loop() |
| 68 | + asyncio.set_event_loop(loop) |
| 69 | + return loop |
70 | 70 |
|
71 | | - asyncio.set_event_loop(loop) |
72 | | - |
| 71 | +def _run_coroutines_in_separate_thread( |
| 72 | + coroutines_task: Coroutine[Any, Any, list[tuple[Any, httpx.Response]]] |
| 73 | +) -> list[httpx.Response]: |
| 74 | + loop = _get_asyncio_loop() |
73 | 75 | return loop.run_until_complete(coroutines_task) |
74 | 76 |
|
| 77 | +def _get_limiter(concurrency_level: int, executor: futures.ThreadPoolExecutor) -> asyncio.Semaphore: |
| 78 | + def _setup_limiter_in_thread_loop(): |
| 79 | + _get_asyncio_loop() |
| 80 | + return asyncio.Semaphore(concurrency_level) |
| 81 | + with executor: |
| 82 | + return executor.submit(_setup_limiter_in_thread_loop).result() |
| 83 | + |
| 84 | + |
75 | 85 |
|
76 | 86 | async def _order_keeper(index: int, coro: Awaitable) -> Tuple[int, httpx.Response]: |
77 | 87 | response = await coro |
@@ -185,6 +195,7 @@ def __init__(self) -> None: |
185 | 195 | self.allow_failed: bool = DEFAULT_ALLOW_FAILED |
186 | 196 | self.cache_tmp_data_feature: bool = DEFAULT_CACHE_TMP_DATA |
187 | 197 | self.cache_tmp_data_dir: str = DEFAULT_CACHE_TMP_DATA_DIR |
| 198 | + self.executor = futures.ThreadPoolExecutor(max_workers=1) |
188 | 199 |
|
189 | 200 | def sdk_init( |
190 | 201 | self, base_url: str, client: HttpClient |
@@ -333,7 +344,7 @@ def before_request( |
333 | 344 | fallback_value=DEFAULT_CONCURRENCY_LEVEL, |
334 | 345 | max_allowed=MAX_CONCURRENCY_LEVEL, |
335 | 346 | ) |
336 | | - limiter = asyncio.Semaphore(concurrency_level) |
| 347 | + limiter = _get_limiter(concurrency_level, self.executor) |
337 | 348 |
|
338 | 349 | self.cache_tmp_data_feature = form_utils.get_split_pdf_cache_tmp_data( |
339 | 350 | form_data, |
@@ -621,7 +632,7 @@ def _await_elements(self, operation_id: str) -> Optional[list]: |
621 | 632 |
|
622 | 633 | # sending the coroutines to a separate thread to avoid blocking the current event loop |
623 | 634 | # this operation should be removed when the SDK is updated to support async hooks |
624 | | - with futures.ThreadPoolExecutor(max_workers=1) as executor: |
| 635 | + with self.executor as executor: |
625 | 636 | task_responses_future = executor.submit(_run_coroutines_in_separate_thread, coroutines) |
626 | 637 | task_responses = task_responses_future.result() |
627 | 638 |
|
|
0 commit comments