Skip to main content
removed typos
Source Link
ThatBrianDude
  • 3.2k
  • 3
  • 22
  • 46

I have a question about a situation I am in currently which I have a solution for but am not quite sure if it 100% solves the issue at hand as I do not have tests written that could validate my solutiongsolution.

socket.on("join_game", data => {
    const game = openGames[data.gameId}

    // game already full 
    if (game.p2) {
        return socket.emit("join_game_reply", {
            err: "Someone else already joined."
        })
    }

    // check if users balance is sufficient to match bet of room creator
    verifyUserBalance(socket.player, game.bet)
        .then(sufficient => {
            if(sufficient){
              // join game
              game.p2 = sockersocket.player
            }
        })
})

I have a question about a situation I am in currently which I have a solution for but am not quite sure if it 100% solves the issue at hand as I do not have tests written that could validate my solutiong.

socket.on("join_game", data => {
    const game = openGames[data.gameId}

    // game already full 
    if (game.p2) {
        return socket.emit("join_game_reply", {
            err: "Someone else already joined."
        })
    }

    // check if users balance is sufficient to match bet of room creator
    verifyUserBalance(socket.player, game.bet)
        .then(sufficient => {
            if(sufficient){
              // join game
              game.p2 = socker.player
            }
        })
})

I have a question about a situation I am in currently which I have a solution for but am not quite sure if it 100% solves the issue at hand as I do not have tests written that could validate my solution.

socket.on("join_game", data => {
    const game = openGames[data.gameId}

    // game already full 
    if (game.p2) {
        return socket.emit("join_game_reply", {
            err: "Someone else already joined."
        })
    }

    // check if users balance is sufficient to match bet of room creator
    verifyUserBalance(socket.player, game.bet)
        .then(sufficient => {
            if(sufficient){
              // join game
              game.p2 = socket.player
            }
        })
})
Improve formatting
Source Link
Stamos
  • 4k
  • 1
  • 25
  • 48

socket.on("join_game", data => { const game = openGames[data.gameId}

socket.on("join_game", data => {
        const game = openGames[data.gameId}

        // game already full 
        if (game.p2) {
            return socket.emit("join_game_reply", {
                err: "Someone else already joined."
            })
        }

        // check if users balance is sufficient to match bet of room creator
        verifyUserBalance(socket.player, game.bet)
            .then(sufficient => {
                if(sufficient){
                  // join game
                  if (game.p2) {
                      return socket.emit("join_game_reply", {
                         err: "Someone else already joined."
                      })
                      game.p2 = socket.player
                  }
                  
                }
            })
    })

socket.on("join_game", data => { const game = openGames[data.gameId}

    // game already full 
    if (game.p2) {
        return socket.emit("join_game_reply", {
            err: "Someone else already joined."
        })
    }

    // check if users balance is sufficient to match bet of room creator
    verifyUserBalance(socket.player, game.bet)
        .then(sufficient => {
            if(sufficient){
              // join game
              if (game.p2) {
                  return socket.emit("join_game_reply", {
                     err: "Someone else already joined."
                  })
                  game.p2 = socket.player
              }
              
            }
        })
})
socket.on("join_game", data => {
        const game = openGames[data.gameId}

        // game already full 
        if (game.p2) {
            return socket.emit("join_game_reply", {
                err: "Someone else already joined."
            })
        }

        // check if users balance is sufficient to match bet of room creator
        verifyUserBalance(socket.player, game.bet)
            .then(sufficient => {
                if(sufficient){
                  // join game
                  if (game.p2) {
                      return socket.emit("join_game_reply", {
                         err: "Someone else already joined."
                      })
                      game.p2 = socket.player
                  }
                  
                }
            })
    })
Source Link
ThatBrianDude
  • 3.2k
  • 3
  • 22
  • 46

NodeJS: Avoiding race condition with async verifications

I have a question about a situation I am in currently which I have a solution for but am not quite sure if it 100% solves the issue at hand as I do not have tests written that could validate my solutiong.

I would love your oppinion on the matter and maybe a suggestion of a more elegant solution or possibly even a way to avoid the issue completely.

Here it is:

I am making a game where you may create or join open rooms/games.

There is a gamelist in the UI and when you click a game you attempt to join that game.

Each game has a bet (amount of credit that you win or lose) that the creator set which anyone joining must match.

On the serverside, before I let the player actually join the room, I must validate that his credit balance is sufficient to match the bet of the game he is joining. This will be via an API call.

Now, if two players join the game at once, lets say the validation of the first player joining takes 3 seconds but the validation of the second only 1 second.

Since rooms are 1 vs 1 I must not let a player join if someone else already did.

I can do this simply by checking if theres a player in the game already:

// game already full 
if (game.p2) {
    return socket.emit("join_game_reply", {
        err: "Someone else already joined."
    })
}

But, the issue at hand is, after that check, I must validate the balance.

So we get something like this:

socket.on("join_game", data => {
    const game = openGames[data.gameId}

    // game already full 
    if (game.p2) {
        return socket.emit("join_game_reply", {
            err: "Someone else already joined."
        })
    }

    // check if users balance is sufficient to match bet of room creator
    verifyUserBalance(socket.player, game.bet)
        .then(sufficient => {
            if(sufficient){
              // join game
              game.p2 = socker.player
            }
        })
})

The issue here:

What if at the time playerX clicks join the game is open, validation starts but while validating playerY joins and finishes validation before playerX and therefore is set as game.p2. Validation of playerX finished shortly after and the server then continues to set game.p2 to playerX, leaving playerY with a UI state of ingame even though on the server he is not anymore.

The solution I have is to literally just do the check again after validation:

socket.on("join_game", data => { const game = openGames[data.gameId}

    // game already full 
    if (game.p2) {
        return socket.emit("join_game_reply", {
            err: "Someone else already joined."
        })
    }

    // check if users balance is sufficient to match bet of room creator
    verifyUserBalance(socket.player, game.bet)
        .then(sufficient => {
            if(sufficient){
              // join game
              if (game.p2) {
                  return socket.emit("join_game_reply", {
                     err: "Someone else already joined."
                  })
                  game.p2 = socket.player
              }
              
            }
        })
})

The reason I think this works is because nodeJS is single threaded and I can therefore make sure that after validating I only let players join if no one else joined in the meantime.

After writing this up I actually feel pretty confident that it will work so please let me in on my mistakes if you see any! Thanks a lot for taking the time!