|
2 | 2 |
|
3 | 3 | # pyright: reportReturnType = false |
4 | 4 | import asyncio |
5 | | -from concurrent.futures import ThreadPoolExecutor |
6 | 5 | from typing_extensions import Protocol, runtime_checkable |
7 | 6 | import httpx |
8 | 7 | from typing import Any, Optional, Union |
@@ -116,21 +115,42 @@ def close_clients( |
116 | 115 | pass |
117 | 116 |
|
118 | 117 | if async_client is not None and not async_client_supplied: |
119 | | - is_async = False |
| 118 | + # First, try the simplest approach - use asyncio.run() |
| 119 | + # This works when we're not in an async context |
120 | 120 | try: |
121 | | - asyncio.get_running_loop() |
122 | | - is_async = True |
123 | | - except RuntimeError: |
124 | | - pass |
125 | | - |
126 | | - try: |
127 | | - # If this function is called in an async loop then start another |
128 | | - # loop in a separate thread to close the async http client. |
129 | | - if is_async: |
130 | | - with ThreadPoolExecutor(max_workers=1) as executor: |
131 | | - future = executor.submit(asyncio.run, async_client.aclose()) |
132 | | - future.result() |
| 121 | + asyncio.run(async_client.aclose()) |
| 122 | + except RuntimeError as e: |
| 123 | + # If we get "RuntimeError: This event loop is already running", |
| 124 | + # it means we're in an async context |
| 125 | + if "already running" in str(e): |
| 126 | + try: |
| 127 | + # We're in an async context, so get the running loop |
| 128 | + loop = asyncio.get_running_loop() |
| 129 | + # Create a task but don't wait for it |
| 130 | + loop.create_task(async_client.aclose()) |
| 131 | + except Exception: |
| 132 | + # If we can't get the loop or create a task, just ignore |
| 133 | + # The GC will eventually clean up the resources |
| 134 | + pass |
| 135 | + # If we get "RuntimeError: There is no current event loop in thread", |
| 136 | + # we're not in an async context, but asyncio.run() failed for some reason |
| 137 | + # In this case, we can try to create a new event loop explicitly |
| 138 | + elif "no current event loop" in str(e): |
| 139 | + try: |
| 140 | + # Create a new event loop and run the coroutine |
| 141 | + loop = asyncio.new_event_loop() |
| 142 | + asyncio.set_event_loop(loop) |
| 143 | + try: |
| 144 | + loop.run_until_complete(async_client.aclose()) |
| 145 | + finally: |
| 146 | + loop.close() |
| 147 | + asyncio.set_event_loop(None) |
| 148 | + except Exception: |
| 149 | + # If this also fails, just ignore |
| 150 | + pass |
| 151 | + # For any other RuntimeError, just ignore |
133 | 152 | else: |
134 | | - asyncio.run(async_client.aclose()) |
| 153 | + pass |
135 | 154 | except Exception: |
| 155 | + # For any other exception, just ignore |
136 | 156 | pass |
0 commit comments