Closed curz46 closed 4 years ago
I've not looked at the structure, but perhaps the guild cache would work well in ETS instead? That way it would it could work in parallel and be faster than just about any other case as well.
I think we should go ahead and integrate 1 as a quick fix to this bug, and then work on moving the cache to ETS or a single process to avoid resorting to workarounds like this.
Description
Alchemy's event module is asynchronous, so two events received at different times can have Alchemy's internal handlers for them executed simultaneously. The guild cache is actually a group of
GenServer
s, exactly one for each guild, storing the state of its guild. A problem arises when you consider how the cache is started:READY
's handler spawns a GenServer for each guild cache, setting it to:%{"id" => "...", "unavailable" => true}
GUILD_CREATE
's handler checks if the GenServer for the relevant guild is running. If it is, then it replaces the cache with the incoming data. If it isn't, then it starts the GenServer with the new data.Currently, it is very often the case that
READY
will finish starting all of the guilds' GenServers afterGUILD_CREATE
does, since they run simultaneously. This means thatGUILD_CREATE
causes the server to be started since it is not already, then filled with the guild's data.READY
then completes its execution, starting the guilds' GenServers without checking if they are already running. This restarts the GenServers and sets them all as unavailable. There is no check in place to see if guilds are still unavailable after X seconds so it remains like this in guild cache forever, with updates to the cache through events just bouncing off of it since there is no structure to it.Why not just change
READY
's handler to only start the guild cache if it is not already started?Consider this timeline of events:
Proposed Solutions
READY
will always be received first (probably a fair assumption). Block the event dispatcher whenREADY
is received by executing the handler synchronously. (Impl. here) (Credit)GenServer
, using one big map for all guilds. This has performance implications, because all operations on the guild cache are on a single process. Potentially significant when a bot is in a large number of guilds.GUILD_CREATE
event. Both guilds the bot is not in and guilds that are unavailable (whether that is at launch or otherwise) do not have GenServers running. Determining whether or not the bot user is in a guild can be done through a list of guild snowflakes managed independently of the guild cache.Dylan