Web Frontend and the job queue

The web frontend handles is a essentially a single php script that simply forwards jobs to play a move, and then returns the next board state back as another chunk of html5 and javascript. The job queue is a simple C++ server that accepts connections from frontends and engines. It accepts connections from engines that waits for new jobs (port 13334), and connections from frontends that submits new jobs (port 13333). What happens in the job queue is that it matches frontend connections with engine connections.

The javascript client sends a POST request to the web frontend, which contains the full sequence of the game (so that the server can be completely stateless – yes, the client keeps the state of the game). What happens next is:

  1. The frontend picks a random job queue.
  2. The POST request is packetized into an internal protocol format.
  3. The web frontend opens a TCP connection to the job queue, and then sends a dummy packet (a single zero).
  4. The job queue accepts the connection, and then puts the connection into a queue. As engines are ready, the queue is drained and assigned to available engines.
  5. When a connection is assigned an engine, the job queue responds to the client with a dummy packet. This signals the web frontend that it is ready to handle a job.
  6. The web frontend sends the game state, which gets forwarded to the engine. The engine does the ‘thinking’ and then returns the next move – either the board coordinate, a pass, or a ‘resign’ response.
  7. The job queue forwards the response back to the web frontend, which gets forwarded back to the client. The connection is closed.

There is a 15-second timeout on each step. If anything goes wrong, the whole sequence is aborted and then the frontend responds to the client with a ‘error-retry’ response. The job queue cleans up any aborted sockets, and the workers also clean up themselves if the socket gets pulled abruptly.

Frontend connections terminate as soon as one job is handled (this is php, I don’t think we can share socket resources between different sessions), while the worker connections are persistent and the connection is kept alive as long as the worker is functional. In case a worker crashes unexpectedly, the worker will be re-launched immediately.

The protocol itself is ultra-simple, and used for both frontend-to-jobqueue communication and jobqueue-to-engine communication. A request/response consists of multiple 16-bit integers where the first integer is always the packet size.

A request packet contains the sequence (board coordinates) of the whole game. To prevent any integer overflows, the server will simply truncate any games longer than 1000 moves into 1000, and it’s the client’s responsibility to prevent any games longer than 1000 moves.

The response is either a zero-length packet (for the dummy handshake) or a one-length packet. We can add other encodings (e.g., komi or other strength settings) but that is something that can be done in the future.

Next part is the engine itself – which is a customized version of leela-zero.

Leave a Reply

Your email address will not be published. Required fields are marked *