Spawning a stream cache server

In this section we will be making use of the Node.js “Child Process” module to spawn Stream Cache Servers as POST requests come into our application server.

An instance of the ts3d_sc_server application is required for every streaming session of the HOOPS Web viewer. This application has a number of configuration options which can be set via the command line, however, for this tutorial we will be focusing on only a small subset of them.

Every time the user makes a POST request to /spawn endpoint we will create a new Stream Cache Server and return its details to the client. This will allow them to create a Communicator.WebViewer object on the viewer and connect to the newly spawned server. Every instance of ts3d_sc_server needs to run on its own unique port for WebSocket and HTTP connections. As well, our application will need to assign unique ports for each instance.

Start by adding the following require statements to the top of spawner.js:

const { spawn } = require('child_process');
const uuidv4 = require('uuid/v4');

Add the following code to the bottom of the Spawner class constructor:

this.wsBasePort = 55000;
this.availableWsPorts = [];
this.activeSpawns = new Map();

We will use these variables to track and assign ports for the instances that we spawn. When a process is spawned, we will check to see if there are any available ports that can be reused. If there are, we will pop one from the appropriate array, otherwise we will allocate a new one. When instances terminate, we will return their ports to the available array and remove it from our active spawns.

In order to track our active spawns, we will make a small class to hold information about each instance that we spawn. Add the SpawnInfo class right above where your Spawner class is declared:

class SpawnInfo {
  constructor(spawnId, wsPort, rendererType, response) {
        this.spawnId = spawnId;
        this.wsPort = wsPort;
        this.rendererType = rendererType;
        this.response = response;
        this.lastPingTime = null;
        this.startTime = new Date();
  }
}

Now that we have a convenient structure for storing information about an instance, we can implement our spawnViewer method:

spawnViewer(req, res) {
  const spawnId = uuidv4();
  let rendererType = "csr";

  const wsPort = this.availableWsPorts.length ? this.availableWsPorts.pop() : this.wsBasePort++;

  const spawnInfo = new SpawnInfo(spawnId, wsPort, rendererType, res);
  this.activeSpawns.set(spawnId, spawnInfo);

  let args = [
        "--id", spawnInfo.spawnId,
        "--sc-port", spawnInfo.wsPort,
        "--model-search-directories", this.modelDirectory,
        "--license-file", this.licenseFile
  ];

  let process = spawn(this.executablePath, args);
  process.on("exit", (code) =>{
        console.log(`spawn ${spawnInfo.spawnId} exited with code: ${code}`);
  });

  res.status(200).json({result: `spawned viewer on websocket port: ${spawnInfo.wsPort}`});
}

Examining the code for this method, we can see that command-line arguments are built up for each viewer instance before they are spawned.

Note

We are temporarily adding an event handler to the child process ‘exit’ event, as well as immediately sending a response to the client. Later in this tutorial we will learn how to receive and process status update events, such as ready and disconnect, from our viewer instances. We will also delay the response to the client until the viewer has started and is ready to receive a WebSocket connection. This will simplify the call from the front-end by making sure the Stream Cache Server is ready to go before the response is sent.

In this tutorial we are specifying only a subset of the possible configuration options for the ts3d_sc_server. Review our Stream Cache Server Command Line Options reference for a complete list.

We now are spawning Stream Cache Servers when the “Create New Viewer” button is pressed. Pressing the button multiple times will cause multiple servers to spawn.

../../_images/tutorial_streaming_server_servers_output.png

The spawned server will terminate automatically if it does not receive an incoming connection in a short period of time. If we wait a moment, we will see corresponding messages in the terminal indicating the Stream Cache Servers have exited cleanly:

spawn 7b2555a7-8ffb-4708-b352-76888cacef1b exited with code: 0
spawn 67d29d6b-cf83-463f-a108-70d2d37d3fdb exited with code: 0
spawn a910b049-2bcd-4292-9d47-9b3770984658 exited with code: 0
spawn ae88bf74-7a54-44f1-9bc9-14e144dbc0ca exited with code: 0

We are now ready to monitor and receive updates from ts3d_sc_server.