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