Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve force exiting (double interrupt) #1745

Merged
merged 5 commits into from
Nov 2, 2023
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changes/1745.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve handing of force exiting a bot (double interrupt)
- Additionally, improve exception message
3 changes: 3 additions & 0 deletions hikari/errors.py
Original file line number Diff line number Diff line change
@@ -102,6 +102,9 @@ class HikariInterrupt(KeyboardInterrupt, HikariError):
signame: str = attrs.field()
"""The signal name that was raised."""

def __str__(self) -> str:
return f"Signal {self.signum} ({self.signame}) received"


@attrs.define(auto_exc=True, repr=False, slots=False)
class ComponentStateConflictError(HikariError):
34 changes: 17 additions & 17 deletions hikari/impl/gateway_bot.py
Original file line number Diff line number Diff line change
@@ -805,10 +805,10 @@ def run(
except AttributeError:
_LOGGER.log(ux.TRACE, "cannot set coroutine tracking depth for sys, no functionality exists for this")

try:
with signals.handle_interrupts(
enabled=enable_signal_handlers, loop=loop, propagate_interrupts=propagate_interrupts
):
with signals.handle_interrupts(
enabled=enable_signal_handlers, loop=loop, propagate_interrupts=propagate_interrupts
):
try:
loop.run_until_complete(
self.start(
activity=activity,
@@ -825,22 +825,22 @@ def run(

loop.run_until_complete(self.join())

finally:
if self._closing_event:
if self._closing_event.is_set():
loop.run_until_complete(self._closing_event.wait())
else:
loop.run_until_complete(self.close())
finally:
if self._closing_event:
if self._closing_event.is_set():
loop.run_until_complete(self._closing_event.wait())
else:
loop.run_until_complete(self.close())

if close_passed_executor and self._executor is not None:
_LOGGER.debug("shutting down executor %s", self._executor)
self._executor.shutdown(wait=True)
self._executor = None
if close_passed_executor and self._executor is not None:
_LOGGER.debug("shutting down executor %s", self._executor)
self._executor.shutdown(wait=True)
self._executor = None

if close_loop:
aio.destroy_loop(loop, _LOGGER)
if close_loop:
aio.destroy_loop(loop, _LOGGER)

_LOGGER.info("successfully terminated")
_LOGGER.info("successfully terminated")

async def start(
self,
34 changes: 17 additions & 17 deletions hikari/impl/rest_bot.py
Original file line number Diff line number Diff line change
@@ -568,10 +568,10 @@ def run(
except AttributeError:
_LOGGER.log(ux.TRACE, "cannot set coroutine tracking depth for sys, no functionality exists for this")

try:
with signals.handle_interrupts(
enabled=enable_signal_handlers, loop=loop, propagate_interrupts=propagate_interrupts
):
with signals.handle_interrupts(
enabled=enable_signal_handlers, loop=loop, propagate_interrupts=propagate_interrupts
):
try:
loop.run_until_complete(
self.start(
backlog=backlog,
@@ -588,22 +588,22 @@ def run(
)
loop.run_until_complete(self.join())

finally:
if self._close_event:
if self._is_closing:
loop.run_until_complete(self._close_event.wait())
else:
loop.run_until_complete(self.close())
finally:
if self._close_event:
if self._is_closing:
loop.run_until_complete(self._close_event.wait())
else:
loop.run_until_complete(self.close())

if close_passed_executor and self._executor:
_LOGGER.debug("shutting down executor %s", self._executor)
self._executor.shutdown(wait=True)
self._executor = None
if close_passed_executor and self._executor:
_LOGGER.debug("shutting down executor %s", self._executor)
self._executor.shutdown(wait=True)
self._executor = None

if close_loop:
aio.destroy_loop(loop, _LOGGER)
if close_loop:
aio.destroy_loop(loop, _LOGGER)

_LOGGER.info("successfully terminated")
_LOGGER.info("successfully terminated")

async def start(
self,
2 changes: 1 addition & 1 deletion hikari/internal/aio.py
Original file line number Diff line number Diff line change
@@ -259,7 +259,7 @@ async def murder(future: asyncio.Future[typing.Any]) -> None:
remaining_tasks = tuple(t for t in asyncio.all_tasks(loop) if not t.done())

if remaining_tasks:
logger.debug("terminating %s remaining tasks forcefully", len(remaining_tasks))
logger.warning("terminating %s remaining tasks forcefully", len(remaining_tasks))
loop.run_until_complete(_gather((murder(task) for task in remaining_tasks)))
else:
logger.debug("No remaining tasks exist, good job!")
7 changes: 5 additions & 2 deletions hikari/internal/signals.py
Original file line number Diff line number Diff line change
@@ -113,9 +113,12 @@ def handle_interrupts(
try:
yield

except errors.HikariInterrupt:
except errors.HikariInterrupt as ex:
if propagate_interrupts:
raise
# Always raise a new clean errors.HikariInterrupt, which is similar
# to what pure Python would do with KeyboardInterrupt
from_ex = ex if not isinstance(ex, errors.HikariInterrupt) else None
raise ex from from_ex

finally:
for sig in _INTERRUPT_SIGNALS: