Sample Application

The sample application is a “dice game”: a game coordinator service will ask two (or more) player services for a random number between 1 and 6. The player with the highest number wins.

The first few chapters of this tutorial will focus on the player service, which is a basic HTTP application, that has an API endpoint /rolldice which returns a random number between 1 and 6 on request.

Create and launch the player service

Let’s begin by setting up a new directory with the source code of the player service:

mkdir player-service
cd player-service

Dependencies

In that new directory, run the following command in a terminal window to initialize a new project, and to add all the dependencies needed.

go mod init dice
npm init -y
npm install express
npm init -y
npm install typescript \
  ts-node \
  @types/node \
  express \
  @types/express

# initialize typescript
npx tsc --init

Code

The player service consists of two files: an application file for the logic of the HTTP server, and a library file that will handle the dice rolling.

First, create the application file named with the following code in it:

/* main.go */
package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/rolldice", rolldice)

	log.Fatal(http.ListenAndServe(":8080", nil))
}
/*app.js*/
const express = require('express');
const { rollTheDice } = require('./dice.js');

const PORT = parseInt(process.env.PORT || '8080');
const app = express();

app.get('/rolldice', (req, res) => {
  const rolls = req.query.rolls ? parseInt(req.query.rolls.toString()) : NaN;
  if (isNaN(rolls)) {
    res
      .status(400)
      .send("Request parameter 'rolls' is missing or not a number.");
    return;
  }
  res.send(JSON.stringify(rollTheDice(rolls, 1, 6)));
});

app.listen(PORT, () => {
  console.log(`Listening for requests on http://localhost:${PORT}`);
});
/*app.ts*/
import express, { Request, Express } from 'express';
import { rollTheDice } from './dice';

const PORT: number = parseInt(process.env.PORT || '8080');
const app: Express = express();

app.get('/rolldice', (req, res) => {
  const rolls = req.query.rolls ? parseInt(req.query.rolls.toString()) : NaN;
  if (isNaN(rolls)) {
    res
      .status(400)
      .send("Request parameter 'rolls' is missing or not a number.");
    return;
  }
  res.send(JSON.stringify(rollTheDice(rolls, 1, 6)));
});

app.listen(PORT, () => {
  console.log(`Listening for requests on http://localhost:${PORT}`);
});

Next, create the library file named with the following code in it:

package main

import (
	"io"
	"log"
	"math/rand"
	"net/http"
	"strconv"
)

func rolldice(w http.ResponseWriter, r *http.Request) {
	roll := 1 + rand.Intn(6)

	resp := strconv.Itoa(roll) + "\n"
	if _, err := io.WriteString(w, resp); err != nil {
		log.Printf("Write failed: %v\n", err)
	}
}
/*dice.js*/
function rollOnce(min, max) {
  return Math.floor(Math.random() * (max - min) + min);
}

function rollTheDice(rolls, min, max) {
  const result = [];
  for (let i = 0; i < rolls; i++) {
    result.push(rollOnce(min, max));
  }
  return result;
}

module.exports = { rollTheDice };

});

app.listen(PORT, () => {
  console.log(`Listening for requests on http://localhost:${PORT}`);
});
/*dice.ts*/
function rollOnce(min: number, max: number) {
  return Math.floor(Math.random() * (max - min) + min);
}

export function rollTheDice(rolls: number, min: number, max: number) {
  const result: number[] = [];
  for (let i = 0; i < rolls; i++) {
    result.push(rollOnce(min, max));
  }
  return result;
}

Test

Build and run the application with the following command

$ node app.js
Listening for requests on http://localhost:8080
$ node app.js
Listening for requests on http://localhost:8080
$ npx ts-node app.ts
Listening for requests on http://localhost:8080

To verify that your player service is running, either open http://localhost:8080/rolldice in your web browser or run the following in the command line:

curl http://localhost:8080/rolldice

For the next sections of the tutorial all you need is the player service, so you can continue with setting up the OpenTelemetry SDK.

You can come back later here, when you will learn how to correlate telemetry across services.

Create and launch the game coordinator

For setting up the game coordinator, create another new directory, that lives side by side with the player service:

cd .. # if you are in the player-service directory
mkdir coordinator-service
cd coordinator-service

Dependencies

The game coordinator has the same dependencies. So, you can run the same code to initialize a new project, and to add all the dependencies needed.

go mod init dice
npm init -y
npm install express
npm init -y
npm install typescript \
  ts-node \
  @types/node \
  express \
  @types/express

# initialize typescript
npx tsc --init

Code

Create the application file named with the following code in it:

Test

To verify that your coordinator service is running and connecting properly to your one player service, run the following in the command line:

./game-coordinator

Since you only have one player service currently running, you will see something like the following printed to the console:

Player 1 wins: 6

Run multiple player services

To have multiple player compete, go back to the folder of the player service and run a second instance:

$ node app.js
Listening for requests on http://localhost:8080
$ node app.js
Listening for requests on http://localhost:8080
$ npx ts-node app.ts
Listening for requests on http://localhost:8080

Next Step

After you have setup your sample application, you can continue with setting up the OpenTelemetry SDK.


Última modificación October 9, 2024: more words (a52ab442)