Skip to content

Commit 5464c43

Browse files
authored
patch cancel bug: immediately mark predictions as cancelled (#1798)
* unconditionally mark predictions as cancelled without waiting for cancellation to succeed while I struggle with #1786, we see queue spikes because not responding to cancellation promptly causes the pod to get restarted. this is a dirty hack to pretend like cancellation works immediately. as soon as we fix the race condition (and possibly any issues with task.cancel() behaving differently from signal handlers), we can drop this. Signed-off-by: technillogue <technillogue@gmail.com> * make Mux.write a sync method this makes the cancel patch cleaner, but might be a small speedup for high-throughput outputs Signed-off-by: technillogue <technillogue@gmail.com> * gate this behind a feature flag --------- Signed-off-by: technillogue <technillogue@gmail.com>
1 parent b9df82a commit 5464c43

2 files changed

Lines changed: 13 additions & 3 deletions

File tree

‎python/cog/server/runner.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,16 @@ def cancel(self, prediction_id: str) -> None:
404404
self._events.send(Cancel(prediction_id))
405405
# maybe this should probably check self._semaphore._value == self._concurrent
406406

407+
# HACK: sometimes, Done events may be dropped due to a race condition with logging
408+
# (or possibly because asyncio cancellation is less strict than signal handlers)
409+
# while we're fixing that, here's a bodge so that we always promptly respond
410+
# to cancellation requests so that director doesn't kill us.
411+
#
412+
# if the real Done event comes through, it shouldn't cause any problems
413+
# it will just stay in an ignored queue in the mux
414+
if os.getenv("COG_FAKE_CANCEL"):
415+
self._mux.write(prediction_id, Done(canceled=True))
416+
407417
_read_events_task: "Optional[asyncio.Task[None]]" = None
408418

409419
def _start_event_reader(self) -> None:
@@ -427,7 +437,7 @@ async def _read_events(self) -> None:
427437
id = "SETUP"
428438
if id == "LOG" and len(self._predictions_in_flight) == 1:
429439
id = list(self._predictions_in_flight)[0]
430-
await self._mux.write(id, event)
440+
self._mux.write(id, event)
431441
# If we dropped off the end off the end of the loop, check if it's
432442
# because the child process died.
433443
if not self._child.is_alive() and not self._terminating.is_set():

‎python/cog/server/worker.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ def __init__(self, terminating: asyncio.Event) -> None:
6060
self.terminating = terminating
6161
self.fatal: Optional[FatalWorkerException] = None
6262

63-
async def write(self, id: str, item: PublicEventType) -> None:
64-
await self.outs[id].put(item)
63+
def write(self, id: str, item: PublicEventType) -> None:
64+
self.outs[id].put_nowait(item)
6565

6666
async def read(
6767
self, id: str, poll: Optional[float] = None

0 commit comments

Comments
 (0)