From 2a73585dfd5d22701e1f525ae5ecff60ef4813bd Mon Sep 17 00:00:00 2001 From: io mintz Date: Thu, 8 Oct 2020 02:48:25 +0000 Subject: [PATCH] cluster startup no longer depend on the first cluster running --- cogs/stats.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/cogs/stats.py b/cogs/stats.py index 02a063b..efdfa45 100644 --- a/cogs/stats.py +++ b/cogs/stats.py @@ -18,20 +18,49 @@ from multiprocessing.shared_memory import ShareableList from discord.ext import commands from bot_bin.stats import BotBinStats +# The resource tracker unlinks shared memory on shutdown and assumes all processes that share memory +# share a parent python process. But this is not necessarily the case: the user might decide to run +# each cluster as a systemd unit for example. We don't want a crash of a single cluster to unlink +# the shared memory segment, so we stub out the resource tracking process here, +# as there's no built in way to disable it. +# See https://bugs.python.org/issue38119 +from multiprocessing import resource_tracker +resource_tracker.ensure_running = lambda: None +resource_tracker.main = lambda: None + class Stats(BotBinStats): def __init__(self, bot): super().__init__(bot) - seq = [0] * self.bot.shard_count if self.is_opener() else None - # Use our user ID as part of the shm name to allow running multiple instances of the bot on the same machine. - self.shlist = ShareableList(seq, name=f'emote-manager-{self.bot.user_id}') + + # Use our user ID as part of the shm name + # to allow running multiple instances of the bot on the same machine. + shm_name = f'emote-manager-{self.bot.user_id}' + if self.is_opener(): + seq = [0] * self.bot.shard_count + try: + self.shlist = ShareableList(seq, name=shm_name) + except FileExistsError: + # The file was probably left open from a previous run of the bot, + # so let's re-attach and wipe the old data. + self.shlist = ShareableList(name=shm_name) + # apparently ShareableLists don't support slicing with None values of `stop` + self.shlist[:self.bot.shard_count] = seq + else: + try: + self.shlist = ShareableList(name=shm_name) + except FileNotFoundError: + # looks like we're the first cluster to start up + seq = [0] * self.bot.shard_count + self.shlist = ShareableList(seq, name=shm_name) + self.count() def is_opener(self): - """return whether this is the process that should open the shared memory""" + """return whether this is the cluster that should open the shared memory""" return 0 in self.bot.shard_ids def is_reporter(self): - """return whether we should report stats to the bot lists""" + """return whether this is the cluster that should report stats to the bot lists""" return self.bot.shard_count - 1 in self.bot.shard_ids def cog_unload(self):