Need suggests about RPC

Hi there.
I want to build a web application and there are several rooms in a hall that can hold a game. The problem is it seems that each room should be independent to handle their business, which means concurrency, but I don’t know how this could be done with RPC.
I do not think it is good to open one RPC service for each room, which means using multiple port.
But if I just use one RPC service and parse the room id in the args, then call the room’s function, the logic is sequential.
Is there any suggest? Thanks.

Hi, @Pierre_Ke, welcome to the Go forum.

What part of your web application needs RPC? Can you do what you want just with requests and responses and web sockets?

But if I just use one RPC service and parse the room id in the args, then call the room’s function, the logic is sequential.

Why not just service each request in a new gorountine?
This is how most servers in Go work.

1 Like

One option may be to use several databases. Depending on what each room should do or store. One for each room. Add database rooms when needed. Connect direct, via REST API or RPC API.

Let’s say the room is for board games. Players in this game should choose to play a card or do some actions in turn.
And what I am doing now is open a RPC Service and register a HALL struct. In this HALL struct, I have a rooms slice. Now, when the a RPC request is coming, the args is like ‘{player: Pierre; roomID: 1; action: skip}’, the hall will parse the roomID then call this room’s handling function.
So what do you mean use several databases? I know I can use Redis ’s SUBSCRIBE&PUBHSIH to build a simple chat system for each room. But I don’t know how it works with RPC?

Sure. It is possible to use web sockets, but the problem is should I open a socket for each room? Does it use several ports?

It is my understanding that web sockets work similarly to the HTTP protocol where multiple clients all connect over the same port 443 and the multiplexing is handled at lower layers of the OSI model. There’s more information on the WebSocket - Wikipedia article, including examples in JavaScript and information about, e.g. the handshake and other implementation details.

As I understand it is about how long the player data will be stored. Will it be persistent, per page or per session? Or is there no need for storing? roomID indicates that there will be some sort of storing. Which means you need some storing - localStorage, REDIS or a real RDMS.

RPC in it self does no storing. You have to use Redis, Postgresql etc to store “room data”. RPC can only fire a function or make a request to another program for utilizing its service.

Let’s make it more specific. In this board game, when it is my turn, I choose ‘use this card’ commend. In my design, I want to use RPC to inform server my choice. But I am thinking, maybe I don’t need RPC in this process? If I use REDIS and SUBSCRIBE a ‘user_id#operation’ channel and a ‘room_id#operation’ channel, clients send this ‘use this card’ commend to ‘room_id#operation’ channel then waiting reply from ‘user_id#operation’. Do you think this is a good implementation?

There is a term in database design that is called “multi-tenant”. You can make this by isolating each tenant (room?) by creating a new sql database for each room. This the best isolation technique. But you can also assign a value to each tenant in the same database. Simpler but not that isolated. Used by many hosting companies AFAIK. I guess that this is what you are going to do?

I can’t think of any reason why that wouldn’t work. The only potential downside I see is that this ties you to Redis, but web sockets are not specific to databases. I checked out golang.org/x/net/websocket and watched this tutorial on YouTube (even though it’s for websocket package - github.com/gorilla/websocket - Go Packages) and, personally, I think I would go this route if I were implementing a similar game:

  • Go channels and, perhaps, a single per-game goroutine within the server to handle the game events:
    • Game looks something like this:
      type Game struct {
          incoming chan *GameEvent
          outgoing []chan<- *GameState
          // whatever other game state you need
      }
      
      // ...
      
      // Subscribe a web socket client to the game.  c is a channel into which
      // updates to the game state will be sent by the Game for the client to
      // receive from and update the browser.  The returned channel should be
      // used by the client to send updates from the web client to the Game.
      func (g *Game) Subscribe(c <-chan *GameState) chan<- *GameEvent { ... }
      
      func (g *Game) run() {
          s := newInitialGameState()
          defer func() {
              for _, out := range g.outgoing {
                  close(out)
              }
          }()
          for ev := range g.incoming {
              s = s.createNewStateFromEvent(ev)
              for _, out := range g.outgoing {
                  out<- s
              }
          }
      
  • WebSockets for interaction between users’ browsers and the server:
    • Server-side, for each web socket, have one goroutine for a reader and another for a writer:
      func createGameWebSocketHandler(g *Game) websocket.Handler {
          outgoingFromGame := make(chan *GameState)
          incomingToGame := g.Subscribe(outgoingFromGame)
          return func(ws *websocket.Conn) {
              go func() {
                  for {
                      ev := &GameEvent{}
                      if err := websocket.JSON.Receive(ws, ev); err != nil {
                          wsErr(ws, err)
                          return
                      }
                      incomingToGame <- ev
                  }
              }()
              for st := range outgoingFromGame {
                  if err := websocket.JSON.Send(ws, st); err != nil {
                      wsErr(ws, err)
                      return
                  }
              }
          }
      }
      

Hi skillian,

You are so kind to make such a detailed reply. And yeah, I think I will try to use sub/pub.

Many thinks
Pierre

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.