feat(bot): ✨ Move messages flushing to a separate process.

This commit is contained in:
Nyeki.py
2024-10-23 21:49:03 -03:00
parent 00404973bf
commit 2ff7021595
7 changed files with 149 additions and 99 deletions
-88
View File
@@ -30,11 +30,6 @@ class Calls(base.Cog):
self.hangup_calls.add_exception_type(exceptions.ConfigurationError)
# self.hangup_calls.start()
self.flush_messages.add_exception_type(exceptions.ConfigurationError)
self.flush_messages.add_exception_type(TypeError)
self.flush_messages.add_exception_type(RuntimeError)
self.flush_messages.start()
def cog_unload(self) -> None:
self.hangup_calls.cancel()
@@ -86,89 +81,6 @@ class Calls(base.Cog):
await models.Channel.filter(id__in=hung_up_channel_ids).update(call_id=None)
await redis.srem(constants.CHANNELS_ONCALL_SET, *hung_up_channel_ids)
@tasks.loop(seconds=15)
async def flush_messages(self, all_calls: bool = False) -> None:
"""Fetches all the pending messages from Redis and flushes them to the DB.
Args:
all_calls (bool, optional): Whether to flush the messages for all calls of all shards.
"""
call_ids = await redis.smembers(constants.CALL_IDS_TO_FLUSH)
# Redis returns bytes.
call_ids = [
int(call_id)
for call_id in call_ids
if all_calls
or (int(call_id) % self.bot.shard_count) - self.bot.shard_ids[0] == 0
]
if len(call_ids) == 0:
return
await redis.srem(constants.CALL_IDS_TO_FLUSH, *call_ids)
pipe = redis.pipeline()
for call_id in call_ids:
pipe.hgetall(constants.CALL_MESSAGES_TEMPLATE % call_id)
pipe.hgetall(constants.CALL_MESSAGE_CONTENTS_TEMPLATE % call_id)
for call_id, (messages, message_contents) in zip(
call_ids, utils.chunks(await pipe.execute(), 2)
):
message_rows: list[models.Message] = []
for message_json in messages.values():
message_rows.append(models.Message(**orjson.loads(message_json)))
message_content_rows: list[models.MessageContent] = []
for message_content_json in message_contents.values():
message_content_rows.append(
models.MessageContent(**orjson.loads(message_content_json))
)
message_rows.sort(key=lambda m: m.id)
message_content_rows.sort(key=lambda mc: mc.message_id)
pipe = redis.pipeline()
pipe.delete(
constants.CALL_MESSAGE_CONTENT_ITERATIONS_TEMPLATE % call_id,
constants.CALL_MESSAGE_CONTENTS_TEMPLATE % call_id,
constants.CALL_MESSAGE_FROM_PROPAGATION_TEMPLATE % call_id,
constants.CALL_MESSAGES_TEMPLATE % call_id,
constants.CALL_MESSAGE_REPLIES_TEMPLATE % call_id,
)
await pipe.execute()
for _ in range(3):
try:
await models.Message.bulk_create(message_rows, batch_size=20)
break
except (
asyncpg.exceptions.PostgresError,
asyncpg.exceptions.InterfaceError,
):
continue
for _ in range(3):
try:
await models.MessageContent.bulk_create(
message_content_rows, batch_size=20
)
break
except (
asyncpg.exceptions.PostgresError,
asyncpg.exceptions.InterfaceError,
):
continue
@commands.command(aliases=["c"])
@commands.guild_only()
@checks.is_unbanned()