Skip to content

Simple circle drawing game to illustrate blue/green deployments and A/B Testing to a large audience using a live programming exercise.

Notifications You must be signed in to change notification settings

wrichter/clickgame

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Instructions

Overview

Key idea of this demo is to use a publicly accessible OpenShift instance where the audience can interact with the application while changes are being made. This is a simple game that allows all users to draw circles on a shared canvas by tapping on the canvas.

The application consists of a browser UI capturing user clicks and drawing circles on behalf of the servers request. Multiple servers can modify messages on the fly and exchange messages among each other via a pub/sub broker.

The architecture looks as follows:

+-------+
|browser+--+
+-------+  |  +------+
           +--+server+--+
+-------+  |  +------+  |
|browser+--+            |
+-------+               |  +------+
                        +--+broker|
+-------+               |  +------+
|browser+--+            |
+-------+  |  +------+  |
           +--+server+--+
+-------+  |  +------+
|browser+--+
+-------+

Instantiate clickgame in namespace

$ oc new-project clickgame
$ oc process -f clickgame.yaml | oc create -f -

Demonstrate App structure

  • server.js is a simple express application to serve static content, containing some javascript code to draw a circle on a canvas.
  • public/index.html is the static HTML page being served

(Optional) Create comment outline

You may want to add the following sequence of comments to the JavaScript code. This will explain the flow of the code, each line can then be augmented/replaced by the actual code:

  1. Client (index.html):

    // create websocket
    // function to reconnect web socket
    // function to send coordinates to server
    // when a message is received from the server, draw a circle
    // when web socket is connected...
    // ...set status message,
    // ...start sending clicks to server,
    // ...start reconnect timer and
    // ...close old socket
    // when connection is closed, stop sending clicks to server
    // when connection is lost, reconnect to server
    
  2. Server (server.js)

    // create websocket server
    // create pub/sub broker connection
    // subscribe to topic on broker and forward any message to websocket clients
    // when broker connection is established...
    // ...start publishing new messages from websocket to topic on broker
    // when the process exits, clean up
    

Adjust client (index.html)

Executing these changes will yield result/index.html.

  1. Remove the <h1> element.

  2. Add to the JavaScript to open a web socket back to the server:

    // create websocket
    function connect(url, oldws) {
      statusline.innerHTML = "connecting..."
      var ws = new WebSocket(url);
    
      //additional code here
    }
    connect('ws://' + window.location.host + '/')
    
  3. Create function to reconnect web socket:

    // function to reconnect web socket
    function reconnectafter(msec) {
      clearTimeout(reconnecttimeout);
      reconnecttimeout = setTimeout(() => { connect(url, ws) }, msec);
    }
    
  4. Send click coordinates to the server (add everything in the connect function, after //additional code here ):

    // function to send coordinates to server
    function click(e) {
      ws.send(JSON.stringify({ x: e.clientX, y: e.clientY }));
    }
    
  5. When message is received via websocket, draw a circle with the specified coordinates, radius and color:

    // when a message is received from the server, draw a circle
    ws.onmessage = function(event) {
      statusline.innerHTML = 'connection #' + numconns + ' ' + event.data;
      var msg = JSON.parse(event.data);
      circle(msg.x, msg.y, msg.radius || 20, msg.color || 'blue');
    }
    
  6. When socket is opened successfully: notify user, add event handler to handle clicks, set timeout to reconnect after 10 seconds and close old socket if necessary:

    // when web socket is connected...
    // ...set status message,
    // ...start sending clicks to server,
    // ...start reconnect timer and
    // ...close old socket
    ws.onopen = function() {
      statusline.innerHTML = 'connection #' + ++numconns;
      canvas.addEventListener("mouseup", click, false);
      reconnectafter(10000);
      if (oldws) oldws.close();
    }
    
  7. Remove mouseup handler when connection is closed:

    // when connection is closed, stop sending clicks to server
    ws.onclose = function() {
      canvas.removeEventListener("mouseup", click, false);
    }
    
  8. Reconnect to server upon connection loss with 1 sec delay:

    // when connection is lost, reconnect to server
    ws.onerror = function() {
      reconnectafter(1000);
    }
    

Adjust server (server.js)

Executing these changes will yield result/server.js.

  1. Create websocket server (add after existing code):

    // create websocket server
    const SocketServer = require('ws').Server;
    const wss = new SocketServer({ server });
    
  2. Create stomp connection to message broker:

    // create pub/sub broker connection
    const stompit = require('stompit');
    const stompconnection = {
      host: 'broker-amq-stomp',
      port: 61613,
      connectHeaders: {
        login: process.env.AMQ_USER,
        passcode: process.env.AMQ_PASSWORD
      }
    }
    
    stompit.connect(stompconnection, (err, stompclient) => {
      if (err) console.log(err);
    
      // additional code here
    });
    
  3. Subscribe to topic and forward all publications to websocket clients (below // additional code here ):

    // subscribe to topic on broker and forward any message to websocket clients
    const topic = { destination: '/topic/SampleTopic' }
    stompclient.subscribe(topic, (err, msg) => {
      msg.readString('UTF-8', (err, body) => {
        console.log('sending: %s', body);
        wss.clients.forEach((wsclient) => { wsclient.send(body); });
      });
    });
    
  4. Publish messages from websocket to topic:

    // when broker connection is established...
    wss.on('connection', (ws) => {
      console.log('Client connected');
      ws.on('close', () => console.log('Client disconnected'));
    
      //additional code here 2
    });
    
  5. When websocket message is received, publish it (add under //additional code here 2 ):

    // ...start publishing new messages from websocket to topic on broker
    ws.on('message', (msg) => {
      console.log('received: %s', msg);
      // adjust message here
      const frame = stompclient.send(topic);
      frame.write(msg);
      frame.end();
    });
    
  6. Ensure cleanup on exit (add on stompclient level):

    // when the process exits, clean up
    process.on('exit', () => { stompclient.disconnect() });
    

Rebuild & demonstrate 'blue' application

  1. Rebuild 'blue' application from current source code:

    $ oc start-build clickgame-blue --from-dir=.
    
  2. Demonstrate the created application - all users should be able to jointly create blue circles by clicking on the canvas.

Build 'green' application & adjust route

  1. Adjust the message to be published (under //adjust message here ):

    var o = JSON.parse(msg);
    o.color = 'green';
    msg = JSON.stringify(o);
    
  2. Build 'green' application from current source code:

    $ oc start-build clickgame-green --from-dir=.
    
  3. Switch from 'blue' to 'green':

    $ oc patch route clickgame -p '{"spec":{"to":{"name":"clickgame-green"}}}'
    
  4. Continue creating circles, all circles should now be blue.

  5. Change route weights to 50% blue/50% green:

    $ oc patch route clickgame -p \
    '{"spec":{"to":{"name":"clickgame-blue","weight":50},
    "alternateBackends":[{"name":"clickgame-green","weight":50,"kind":"Service"}]}}'
    
  6. Continue creating circles, 50% should now be blue and 50% should be green.

Reset Demo

  1. $ git checkout public/index.html server.js
  2. $ oc delete all,templates --all

About

Simple circle drawing game to illustrate blue/green deployments and A/B Testing to a large audience using a live programming exercise.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published