-
Notifications
You must be signed in to change notification settings - Fork 1
Error handling and making atomic changes to state #9
Description
In setting up the server, I'm running into the question of how to do error handling in a way that ensures all state changes are atomic. When handling user input, we have to be careful not to partially-apply any changes before we reject an invalid input, lest we leave the server in an inconsistent state. This is easy to do by accident when using the ? operator to propagate errors upward, as we'd like to do in most cases:
pub fn do_a_thing(&mut self) -> anyhow::Result<()> {
// Do a thing that modifies state.
self.state.make_changes();
// Do a thing that might fail and propagate any error that occurs.
self.state.thing_that_fails()?;
// Broadcast the state updates to the clients.
self.clients.broadcast_changes();
}The above is an example of a fairly common case that I've noticed: If we apply some changes to the server's local state and then early-return for error propagation before we broadcast the state changes to the clients, the game is left in an inconsistent state where the server thinks an action has occurred but none of the clients know about it.
The main issue here is that any changes to server state need to be atomic: They either happen completely if successful or don't happen at all if an error occurs. For any given case where this happens there's usually a fairly simple solution, such as manually checking for errors and rolling back changes if one occurs. The focus of this ticket is instead to try to track patterns around where these cases come up and determine what patterns we can employ to make it less likely that we'll accidentally write code with this kind of error.