aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Chris Lovering <[email protected]>2022-04-18 17:26:27 +0100
committerGravatar Chris Lovering <[email protected]>2022-04-18 17:47:20 +0100
commitd62c17b87490500b0d256a2148eb360fe89b81cf (patch)
tree5b94165e3a807c3530ff3d706d58863cde71a544
parentUse discord.py's async cog loading for more cogs (diff)
Refactor otn cog to use discord.py tasks
-rw-r--r--bot/exts/fun/off_topic_names.py65
1 files changed, 30 insertions, 35 deletions
diff --git a/bot/exts/fun/off_topic_names.py b/bot/exts/fun/off_topic_names.py
index d8111bdf5..db03a6620 100644
--- a/bot/exts/fun/off_topic_names.py
+++ b/bot/exts/fun/off_topic_names.py
@@ -1,12 +1,10 @@
import difflib
-from datetime import timedelta
+from datetime import time
-import arrow
from botcore.site_api import ResponseCodeError
-from botcore.utils import scheduling
from discord import Colour, Embed
+from discord.ext import tasks
from discord.ext.commands import Cog, Context, group, has_any_role
-from discord.utils import sleep_until
from bot.bot import Bot
from bot.constants import Channels, MODERATION_ROLES
@@ -18,23 +16,40 @@ CHANNELS = (Channels.off_topic_0, Channels.off_topic_1, Channels.off_topic_2)
log = get_logger(__name__)
-async def update_names(bot: Bot) -> None:
- """Background updater task that performs the daily channel name update."""
- while True:
- # Since we truncate the compute timedelta to seconds, we add one second to ensure
- # we go past midnight in the `seconds_to_sleep` set below.
- today_at_midnight = arrow.utcnow().replace(microsecond=0, second=0, minute=0, hour=0)
- next_midnight = today_at_midnight + timedelta(days=1)
- await sleep_until(next_midnight.datetime)
+class OffTopicNames(Cog):
+ """Commands related to managing the off-topic category channel names."""
+
+ def __init__(self, bot: Bot):
+ self.bot = bot
+ self.updater_task = None
+
+ # What errors to handle and restart the task using an exponential back-off algorithm
+ self.update_names.add_exception_type(ResponseCodeError)
+ self.update_names.start()
+
+ async def cog_unload(self) -> None:
+ """
+ Gracefully stop the update_names task.
+
+ Clear the exception types first, so that if the task hits any errors it is not re-attempted.
+ """
+ self.update_names.clear_exception_types()
+ self.update_names.stop()
+
+ @tasks.loop(time=time(), reconnect=True)
+ async def update_names(self) -> None:
+ """Background updater task that performs the daily channel name update."""
+ await self.bot.wait_until_guild_available()
try:
- channel_0_name, channel_1_name, channel_2_name = await bot.api_client.get(
+ channel_0_name, channel_1_name, channel_2_name = await self.bot.api_client.get(
'bot/off-topic-channel-names', params={'random_items': 3}
)
except ResponseCodeError as e:
log.error(f"Failed to get new off topic channel names: code {e.response.status}")
- continue
- channel_0, channel_1, channel_2 = (bot.get_channel(channel_id) for channel_id in CHANNELS)
+ raise
+
+ channel_0, channel_1, channel_2 = (self.bot.get_channel(channel_id) for channel_id in CHANNELS)
await channel_0.edit(name=f'ot0-{channel_0_name}')
await channel_1.edit(name=f'ot1-{channel_1_name}')
@@ -44,26 +59,6 @@ async def update_names(bot: Bot) -> None:
f" {channel_0_name}, {channel_1_name} and {channel_2_name}"
)
-
-class OffTopicNames(Cog):
- """Commands related to managing the off-topic category channel names."""
-
- def __init__(self, bot: Bot):
- self.bot = bot
- self.updater_task = None
-
- async def cog_unload(self) -> None:
- """Cancel any running updater tasks on cog unload."""
- if self.updater_task is not None:
- self.updater_task.cancel()
-
- async def cog_load(self) -> None:
- """Start off-topic channel updating event loop if it hasn't already started."""
- await self.bot.wait_until_guild_available()
- if self.updater_task is None:
- coro = update_names(self.bot)
- self.updater_task = scheduling.create_task(coro, event_loop=self.bot.loop)
-
@group(name='otname', aliases=('otnames', 'otn'), invoke_without_command=True)
@has_any_role(*MODERATION_ROLES)
async def otname_group(self, ctx: Context) -> None: