Re: Looking for architecture/infrastructure advice on coping with thousands of concurrent clients
Mikael Brockman <mbrock <at> goula.sh>
2014-07-16 12:47:03 GMT
Alois Cochard <alois.cochard <at> gmail.com> writes:
> Hi Isak,
> On 9 July 2014 18:40, Isak Hansen <isak.hansen <at> gmail.com> wrote:
> #2 - I'm new to Haskell and would appreciate thoughts on how to
> store and process game state. Imagine a plain application managing
> 1000 tables of poker, responding to player input (that magically
> appears) and timer events (e.g. folding players that fail to take
> action). What data structures and libraries should I be looking at
> here? Thoughts on concurrency and how I organize program flow?
> If I had to build an system like this, the main design principle I
> would adopt is to not try to share the state of games among nodes, but
> instead redirect players of the same game on the same node (where you
> basically have a thread processing the event of the game and updating
> the state in memory).
> Then I would probably use some form of event sourcing to record game
> action which could be use in case of node crash to recreate a game
> state by replaying events.
> The event source could then be used as well to generate stats/views in
> near real-time.
Some related thoughts:
For poker, it seems reasonable to organize the program around a function
step :: Game -> Event -> (Game, Response)
This would be the entry point for the game logic. It's obvious how to
write tests for this function, and if you're sure that it does the right
thing, then you'll be confident about your game loop.
Then you need a way to produce a sequence of events, combined from
different sources: timers, HTTP requests, etc. If every game is fed by
a `TChan`, for example, then you can write events into that from
different sources. But from the viewpoint of the core logic, this is
just an abstract source of events.
Given the performance of GHC's threads, I don't think thousands of
concurrent clients is that much different from dozens or hundreds -- yet
another reason to avoid premature optimization and focus on clarity and
By the way, I've had fun using `pipes`, `stm`, and `async` to implement
an event sourcing server using JSON commands from web requests. Using
pipe combinators and queues, the data/control flow of the server can be
apparent from the code of the main function, which is something I've
rarely seen in non-Haskell servers!