Matchmaking system experiencing unreliability in game:BindToClose()

I’m currently working on a matchmaking system for a game. The way this works is by having one place in a game act as the lobby. For testing purposes I’ve limited the size of the place to 1 player so I can test on my pc and phone. One server instance of this place becomes the host. The host is responsible for managing players who are currently in a matchmaking queue as well as all other servers (I call these generic servers). The way a server decides if it is a host or not is via a datastore. If checks a datastore to see if HostExists is currently set to true, false, or nil. If it is false or nil then it knows to set itself as the host. If it is true then the server remains generic. Based off if a server is the host or not I then subscribe to a bunch of MessagingService topics.

The problem comes in when a server instance is closing. If a lobby that is the host is closing it uses game:BindToClose() to do a few things. First it will set the HostExists key in the datastore to false. Then it requests a rehost by sending data to a random generic server. This all works good the majority of the time. However, every 1 in 5 or so tests nothing appears to execute. The datastore value will remain true meaning no other host gets set again until I manually reset the value. I have no actual way to do troubleshooting since this function gets called after my player has left the game and the server instance is closing therefore I can’t just print() values to test. I’ve also had problems where rehosting will occur but not the datastore value being changed.

I have no idea why this is so unreliable. My guess is maybe asynchronous methods have weird functionality in this method but that doesn’t make sense it should either work or not work. I was hoping someone with more experience could help out. Here’s the specific code:

-- Handle host closing
game:BindToClose(function()
    if (self.isHost) then
        -- Set the host to stop existing
        HOST_SERVER_DS:SetAsync('HostExists', false)

        -- If other servers exist
        if (#activeServers > 0) then
            -- Request a rehost
            local rehostServer = activeServers[math.random(1, #activeServers)]
            self:_SendRehostRequest(rehostServer)
        end
    else
        -- Remove the generic server from the active list
        self:_SendServerRemoved()
    end
end)
1 Like

I’m not sure if this is the cause of your problem, but according to MessagingService documentation:

Delivery is best effort and not guaranteed. Make sure to architect your game so delivery failures are not critical.

I would also put a wait(10) at the end of the BindToClose function to make sure any background execution finishes before the server is terminated.


If nothing works, HttpService is an alternative for server-to-server communication. But that would require that you host an external server too.

2 Likes

The actual system itself works fine. MessagingService isn’t the problem it’s the way I’m handling the host server. game:BindToClose() is just really unreliable and if it doesn’t trigger on the host then I have to go into studio and manually reset the HostExists value since it never got set back to false. I can’t seem to find any alternatives though.

Since making the original post I’ve narrowed the problem down to the server closing as a result of all players being teleported to the actual game once there’s enough players in the queue. While I could use a workaround and check player count after teleporting then handle what needs to be handled I really wish there was a better alternative.

EDIT: After looking more into it I actually think HTTP service is the way to go. I’ll be porting the entire system over. 500 HTTP requests per minute ensures I’ll never be rate limited & having all the code handled externally means I no longer have to rely on DataStores for checking the existence of a host.