Is updating a map frequently and saving in cache is alright?

We are developing a game, using elixir and phoenix channels as backend, it is a turn based game.

Player joins to lobby channel after starting the game, when a new game starts a genserver is created and players got joined to a new game channel.

We are using Nebulex for caching our game state, while genserver is used for keeping track of timing for single game instance. If genserver crashed for any reason, it will be restarted by supervisor but restore its state from Nebulex cache.

The state in cache is stored as map as value and game id as key :
game_state = %{
playing_players_ids: [1,2,3],
players_on_table_ids: [1,2,3,4],
numbers_of_players: 3,
round_scores: %{ 1 => %{1: 2, 2: 1, 3: 5}, 2 => %{1: 2, 2: 1, 3: 5}},
players_turn: %{1 => 2, 2 => 3, 3 => 1},
players_local_to_global_ids: %{1 => 51, 2 => 41, 3 => 56},
players_global_to_local_ids: %{51 => 1, 41 => 2, 56 => 3},
next_turn_id: 2,
rounds_played: 1,
first_card_suit: “”,
last_turn_winner: 2,
number_of_cards_played: 1,
last_turn_cards: %{1: “H5”, 2: “H1”, 3: “H10”},
bet_info: %{single_bet_amount: 30, collected_amount: 90}
genserver_pid: #PID<0.104.0>
Cache.set(game_id, game_state)

After every player turn, we have to update the state. Get state from cache, update one or more value and save it again in cache. The problem is: to update a single value, an entire map is recreated because of elixir immutability when saved in cache.

We want to know, is it ok? or is there any other way we can implement this?

Also let us know, if this application structure can be improved.


When I wrote a game I didn’t save intermediary results to persistent DB. If something fails then system sends report to Sentry or other similar service using terminate callback, game ends and that’s it. Why? Usually when GenServer fails while working only with internal data and pure functions (no calls to other services which may fail) it means that you have a state and some action which you can’t handle. Saving state and applying the same action won’t help you in reliability. Server will be failed again and again. And even if you restore state and force player to perform another action - this game is not fair, because player has fewer decisions to perform and this has some impact on statistics.
If you really need to have persistent state I’d recommend storing a sequence of actions and initial state. By applying these actions to initial state you’ll get the final one. This approach allows you to store actions asynchronously. Also, it provides better info for debugging and gathering statistics.