mirror of https://github.com/nocturn9x/giambio.git
Starting to work on proper cancellation
This commit is contained in:
parent
7d3b5da90f
commit
77268f63bf
|
@ -107,8 +107,10 @@ class AsyncScheduler:
|
|||
): # Schedules tasks that are waiting on events
|
||||
self.check_events()
|
||||
except CancelledError as cancelled:
|
||||
if cancelled.args[0] in self.tasks:
|
||||
self.tasks.remove(cancelled.args[0]) # Remove the dead task
|
||||
task = cancelled.args[0]
|
||||
task.cancelled = True
|
||||
if task in self.tasks:
|
||||
self.tasks.remove(task) # Remove the dead task
|
||||
self.tasks.append(self.current_task)
|
||||
except StopIteration as e: # Coroutine ends
|
||||
self.current_task.result = e.args[0] if e.args else None
|
||||
|
@ -238,7 +240,9 @@ class AsyncScheduler:
|
|||
def sleep(self, seconds: int or float):
|
||||
"""Puts the caller to sleep for a given amount of seconds"""
|
||||
|
||||
if seconds:
|
||||
if seconds < 0:
|
||||
raise ValueError("the delay can't be negative")
|
||||
elif seconds:
|
||||
self.current_task.status = "sleep"
|
||||
self.paused.put(self.current_task, seconds)
|
||||
else:
|
||||
|
@ -276,8 +280,12 @@ class AsyncScheduler:
|
|||
"sleep",
|
||||
"I/O",
|
||||
): # It is safe to cancel a task while blocking
|
||||
task.cancelled = True
|
||||
task.throw(CancelledError(task))
|
||||
try:
|
||||
task.throw(CancelledError(task))
|
||||
except Exception as error:
|
||||
task.cancelled = True # The task died
|
||||
self.tasks.append(self.current_task)
|
||||
task.exc = error
|
||||
else:
|
||||
task.status = "cancel" # Cancellation is deferred
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from ._core import AsyncScheduler
|
||||
from .exceptions import ErrorStack
|
||||
from .exceptions import ErrorStack, CancelledError
|
||||
import itertools
|
||||
|
||||
|
||||
|
@ -20,18 +20,22 @@ class TaskManager(object):
|
|||
async def _cancel_and_raise(self, err):
|
||||
"""Cancels all tasks and raises an exception"""
|
||||
|
||||
exc = ErrorStack()
|
||||
errors = []
|
||||
for task in itertools.chain(
|
||||
self.scheduler.tasks.copy(),
|
||||
self.scheduler.paused.items(),
|
||||
*self.scheduler.event_waiting.values()
|
||||
self.scheduler.event_waiting.values(),
|
||||
):
|
||||
await task.cancel()
|
||||
try:
|
||||
await task.cancel()
|
||||
except Exception as err:
|
||||
exc.errors.append(err)
|
||||
if exc.errors:
|
||||
exc.errors.insert(err, 0)
|
||||
await task.join()
|
||||
except Exception as fault:
|
||||
fault.__cause__ = None # We clear this to avoid unrelated tracebacks
|
||||
errors.append(fault)
|
||||
if errors:
|
||||
exc = ErrorStack()
|
||||
errors.insert(0, err)
|
||||
exc.errors = errors
|
||||
raise exc
|
||||
raise err
|
||||
|
||||
|
|
|
@ -24,14 +24,25 @@ async def countup(stop: int, step: int = 1):
|
|||
raise ValueError("Ciao")
|
||||
|
||||
|
||||
async def countdown2(n: int):
|
||||
while n > 0:
|
||||
print(f"Down {n}")
|
||||
n -= 1
|
||||
await giambio.sleep(1)
|
||||
raise Exception("bruh")
|
||||
print("Countdown over")
|
||||
return 0
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
async with giambio.TaskManager(scheduler) as manager:
|
||||
cdown = manager.create_task(countdown(10))
|
||||
cup = manager.create_task(countup(5, 2))
|
||||
cdown = manager.create_task(countdown(10))
|
||||
# cdown2 = manager.create_task(countdown2(5))
|
||||
print("Counters started, awaiting completion")
|
||||
except Exception:
|
||||
print("Exceptions propagate!")
|
||||
except Exception as err:
|
||||
print(f"An error occurred!\n{type(err).__name__}: {err}")
|
||||
print("Task execution complete")
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue