Starting to work on proper cancellation

This commit is contained in:
nocturn9x 2020-07-14 21:14:59 +00:00
parent 7d3b5da90f
commit 77268f63bf
3 changed files with 39 additions and 16 deletions

View File

@ -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

View File

@ -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

View File

@ -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")