Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b9d483c
Watchchannel: Moved message consuming task cancelling exception
ks129 Jun 20, 2020
ac302d3
Infractions: Fix cases when user leave from guild before assigning roles
ks129 Jun 20, 2020
429cc86
Implement bot closing tasks waiting + breaking `close` to multiple parts
ks129 Jun 20, 2020
177e4d4
Reddit: Remove unnecessary revoke task name changing
ks129 Jun 21, 2020
1fd30fa
Reddit: Don't define revoke task as variable but instantly append
ks129 Jun 21, 2020
f4004d8
Silence: Add mod alert sending to `closing_tasks` to avoid error
ks129 Jun 21, 2020
b040a38
Add copyright about `_remove_extension` + make function private
ks129 Jul 23, 2020
360ce80
Improve extension + cogs removing comment on `close`
ks129 Jul 23, 2020
65c4312
Simplify bot shutdown cogs removing
ks129 Jul 31, 2020
2dc0ee1
Use asyncio.gather instead manual looping and awaiting
ks129 Jul 31, 2020
040ac42
Make bot shutdown remove all other non-extension cogs again
ks129 Oct 9, 2020
97e5e8c
Merge remote-tracking branch 'up/master' into bug-fixes
ks129 Oct 9, 2020
ff5c90b
Fix calling extensions removing function with wrong name
ks129 Oct 9, 2020
5a5a948
Fix name of extensions removing function
ks129 Oct 10, 2020
b702618
Get all extensions first for unloading to avoid iteration error
ks129 Oct 10, 2020
d0af250
Use done callback instead of plain try-except inside function
ks129 Oct 10, 2020
8ed147c
Catch HTTPException when muting user
ks129 Oct 10, 2020
5256f6b
Merge remote-tracking branch 'origin/bug-fixes' into bug-fixes
ks129 Oct 10, 2020
7301ebc
Merge branch 'master' into bug-fixes
ks129 Nov 7, 2020
027666f
Remove both cogs and extensions on closing
ks129 Nov 7, 2020
d15c4fc
Use result instead exception for watchchannel closing task
ks129 Nov 7, 2020
6a81f71
Catch not found exception in scheduler
ks129 Nov 7, 2020
7c218c2
Merge branch 'master' into bug-fixes
ks129 Nov 21, 2020
8a28656
Merge NotFound caching with HttpException caching with status code
ks129 Dec 2, 2020
50db55d
Fix user leaving from guild log grammar
ks129 Dec 2, 2020
7c2ceed
Log exception instead warning for unexpected HttpException
ks129 Dec 2, 2020
fc59307
Remove second unnecessary parenthesis
ks129 Dec 2, 2020
eb73d30
Add failure message when applying infraction fails because user left
ks129 Dec 2, 2020
690ccd2
Fix removing extensions and cogs for bot shutdown
ks129 Dec 2, 2020
00ff573
Remove unnecessary f-string
ks129 Dec 2, 2020
eb3205d
Merge branch 'master' into bug-fixes
ks129 Dec 2, 2020
0f294d9
Merge branch 'master' into bug-fixes
ks129 Dec 17, 2020
9d96d49
Log info instead error for watchchannel consume task cancel
ks129 Dec 17, 2020
66ea8a3
Merge branch 'master' into bug-fixes
ks129 Dec 29, 2020
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
20 changes: 19 additions & 1 deletion bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import socket
import warnings
from collections import defaultdict
from typing import Dict, Optional
from contextlib import suppress
from typing import Dict, List, Optional

import aiohttp
import discord
Expand Down Expand Up @@ -70,6 +71,9 @@ def _connect_statsd(self, statsd_url: str, retry_after: int = 2, attempt: int =
attempt + 1
)

# All tasks that need to block closing until finished
self.closing_tasks: List[asyncio.Task] = []

async def cache_filter_list_data(self) -> None:
"""Cache all the data in the FilterList on the site."""
full_cache = await self.api_client.get('bot/filter-lists')
Expand Down Expand Up @@ -145,6 +149,20 @@ def clear(self) -> None:

async def close(self) -> None:
"""Close the Discord connection and the aiohttp session, connector, statsd client, and resolver."""
# Done before super().close() to allow tasks finish before the HTTP session closes.
for ext in list(self.extensions):
with suppress(Exception):
self.unload_extension(ext)

for cog in list(self.cogs):
with suppress(Exception):
self.remove_cog(cog)

# Wait until all tasks that have to be completed before bot is closing is done
log.trace("Waiting for tasks before closing.")
await asyncio.gather(*self.closing_tasks)

# Now actually do full close of bot
await super().close()

if self.api_client:
Expand Down
2 changes: 1 addition & 1 deletion bot/exts/info/reddit.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def cog_unload(self) -> None:
"""Stop the loop task and revoke the access token when the cog is unloaded."""
self.auto_poster_loop.cancel()
if self.access_token and self.access_token.expires_at > datetime.utcnow():
asyncio.create_task(self.revoke_access_token())
self.bot.closing_tasks.append(asyncio.create_task(self.revoke_access_token()))

async def init_reddit_ready(self) -> None:
"""Sets the reddit webhook when the cog is loaded."""
Expand Down
34 changes: 29 additions & 5 deletions bot/exts/moderation/infraction/_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,21 @@ async def reapply_infraction(
return

# Allowing mod log since this is a passive action that should be logged.
await apply_coro
log.info(f"Re-applied {infraction['type']} to user {infraction['user']} upon rejoining.")
try:
await apply_coro
except discord.HTTPException as e:
# When user joined and then right after this left again before action completed, this can't apply roles
if e.code == 10007 or e.status == 404:
log.info(
f"Can't reapply {infraction['type']} to user {infraction['user']} because user left the guild."
)
else:
log.exception(
f"Got unexpected HTTPException (HTTP {e.status}, Discord code {e.code})"
f"when awaiting {infraction['type']} coroutine for {infraction['user']}."
)
else:
log.info(f"Re-applied {infraction['type']} to user {infraction['user']} upon rejoining.")

async def apply_infraction(
self,
Expand Down Expand Up @@ -178,6 +191,10 @@ async def apply_infraction(
log_msg = f"Failed to apply {' '.join(infr_type.split('_'))} infraction #{id_} to {user}"
if isinstance(e, discord.Forbidden):
log.warning(f"{log_msg}: bot lacks permissions.")
elif e.code == 10007 or e.status == 404:
log.info(
f"Can't apply {infraction['type']} to user {infraction['user']} because user left from guild."
)
else:
log.exception(log_msg)
failed = True
Expand Down Expand Up @@ -352,9 +369,16 @@ async def deactivate_infraction(
log_text["Failure"] = "The bot lacks permissions to do this (role hierarchy?)"
log_content = mod_role.mention
except discord.HTTPException as e:
log.exception(f"Failed to deactivate infraction #{id_} ({type_})")
log_text["Failure"] = f"HTTPException with status {e.status} and code {e.code}."
log_content = mod_role.mention
if e.code == 10007 or e.status == 404:
Comment thread
Xithrius marked this conversation as resolved.
log.info(
f"Can't pardon {infraction['type']} for user {infraction['user']} because user left the guild."
)
log_text["Failure"] = "User left the guild."
log_content = mod_role.mention
else:
log.exception(f"Failed to deactivate infraction #{id_} ({type_})")
log_text["Failure"] = f"HTTPException with status {e.status} and code {e.code}."
log_content = mod_role.mention
Comment thread
ks129 marked this conversation as resolved.

# Check if the user is currently being watched by Big Brother.
try:
Expand Down
17 changes: 10 additions & 7 deletions bot/exts/moderation/watchchannels/_watchchannel.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,11 +342,14 @@ def cog_unload(self) -> None:
"""Takes care of unloading the cog and canceling the consumption task."""
self.log.trace("Unloading the cog")
if self._consume_task and not self._consume_task.done():
def done_callback(task: asyncio.Task) -> None:
"""Send exception when consuming task have been cancelled."""
try:
task.result()
except asyncio.CancelledError:
self.log.info(
f"The consume task of {type(self).__name__} was canceled. Messages may be lost."
)

self._consume_task.add_done_callback(done_callback)
self._consume_task.cancel()
try:
self._consume_task.result()
except asyncio.CancelledError as e:
self.log.exception(
"The consume task was canceled. Messages may be lost.",
exc_info=e
)