Skip to content

Commit a7415b5

Browse files
author
Michael Kryukov
committed
fix: normalized how exceptions are handled
1 parent 8d8e3b7 commit a7415b5

File tree

5 files changed

+51
-12
lines changed

5 files changed

+51
-12
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Tasks will only be submited when there are available workers (specified by
1313
tasks than amount of available workers (so workers won't have to wait for
1414
task creation). Refer to `tests/test_queue.py` for details.
1515

16+
Exceptions inside of the tasks craeted with executors are ignored. Refer
17+
to `tests/test_exceptions.py` for details.
18+
1619
## Example / Showcase
1720

1821
```py

bounded_pool/__init__.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from abc import ABC
55
from asyncio import Semaphore, Task, create_task
66
from concurrent.futures import Executor, ProcessPoolExecutor, ThreadPoolExecutor
7-
from typing import List, Optional
7+
from typing import Optional
88

99

1010
class BoundedExecutor(ABC):
@@ -31,27 +31,24 @@ def _get_default_max_workers():
3131
return min(32, (os.cpu_count() or 1) + 4)
3232

3333
async def __aenter__(self):
34-
self._tasks: List[Task] = []
3534
self._semaphore = Semaphore(self._semaphore_size)
3635
return self
3736

3837
async def __aexit__(self, exc_type, exc_value, traceback):
39-
while self._tasks:
40-
await self._tasks.pop()
38+
# make sure no tasks being executed
39+
for _ in range(self._semaphore_size):
40+
await self._semaphore.acquire()
4141

4242
async def _acquire(self):
4343
await self._semaphore.acquire()
4444

4545
def _release(self, fut):
46-
if fut in self._tasks:
47-
self._tasks.remove(fut)
4846
self._semaphore.release()
4947

5048
async def submit(self, coro, *args, **kwargs) -> Task:
5149
await self._acquire()
5250
task = create_task(coro(*args, **kwargs))
5351
task.add_done_callback(self._release)
54-
self._tasks.append(task)
5552
return task
5653

5754

tests/test_basic.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,12 @@ async def test_asyncio_executor_sleeps():
2121
for _ in range(2):
2222
await pool.submit(asyncio.sleep, 1)
2323

24-
assert not pool._tasks
25-
2624
async with aassert_takes(more=3.5):
2725
async with BoundedAsyncioPoolExecutor(1) as pool:
2826
async with aassert_takes(more=3):
2927
for _ in range(4):
3028
await pool.submit(asyncio.sleep, 1)
3129

32-
assert not pool._tasks
33-
3430

3531
@pytest.mark.parametrize('cls', [BoundedThreadPoolExecutor, BoundedProcessPoolExecutor])
3632
def test_sync_executor_sleeps(cls):

tests/test_exceptions.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import pytest
2+
3+
from bounded_pool import (
4+
BoundedAsyncioPoolExecutor,
5+
BoundedProcessPoolExecutor,
6+
BoundedThreadPoolExecutor,
7+
)
8+
9+
10+
def raiser():
11+
raise ValueError()
12+
13+
14+
async def araiser():
15+
raise ValueError()
16+
17+
18+
@pytest.mark.anyio
19+
async def test_asyncio_executor_ignores_exceptions():
20+
async with BoundedAsyncioPoolExecutor() as pool:
21+
task = await pool.submit(araiser)
22+
23+
with pytest.raises(ValueError):
24+
await task
25+
26+
task = await pool.submit(araiser)
27+
28+
with pytest.raises(ValueError):
29+
await task
30+
31+
32+
@pytest.mark.parametrize('cls', [BoundedThreadPoolExecutor, BoundedProcessPoolExecutor])
33+
def test_sync_executor_ignores_exceptions(cls):
34+
with cls() as pool:
35+
task = pool.submit(raiser)
36+
37+
with pytest.raises(ValueError):
38+
task.result()
39+
40+
task = pool.submit(raiser)
41+
42+
with pytest.raises(ValueError):
43+
task.result()

tests/test_queue.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ async def test_asyncio_executor_queues():
2323

2424

2525
@pytest.mark.parametrize('cls', [BoundedThreadPoolExecutor, BoundedProcessPoolExecutor])
26-
def test_sync_executor_sleeps(cls):
26+
def test_sync_executor_queues(cls):
2727
with cls(1, 1) as pool:
2828
with assert_takes(more=1, less=2):
2929
with assert_takes(less=0.5):

0 commit comments

Comments
 (0)