Lock by player's UUID when creating/saving/terminating sessions from listeners. This is done by adding new methods to the
SessionManager to perform these actions safely.
Presently, session management is unsafe and can potentially result in duplicated sessions. When a player joins or leaves, their currently stored session is updated. However, there is also an attempt to handle a previous unterminated session, if it exists, leading to the following problems:
- If a player leaves right after joining, before their new session is saved, then a duplicate session may be created. The initial, ID-less session is stored in case it fails to save to the API. On quit, an attempt is made to save this session; as both the join and quit requests contain no ID, two sessions are created for the single login, although one will have no end time.
- If a player reconnects whilst still connected (ie client times out before server), the wrong session may be terminated and have the wrong termination time. If the join task executes before the quit task, the new join session will be terminated by the quit request. Consequently, the session will be considered terminated right after it has begun.
- If a player reconnects whilst still connected (ie client times out before server), then a duplicate session may be created. As the new session starts off without an ID, the quit task may attempt to terminate it at the same time as the join task creates it, creating two sessions for a single login.
The solution is to lock by player UUID, ensuring that at any given time, only a single session may be created or terminated for each player. Different players' sessions may still be manipulated concurrently.