improvment: added prometheus metrics for the number of groups in a room
This commit is contained in:
parent
6658e2d666
commit
b1d2543631
@ -1,5 +1,4 @@
|
|||||||
import {App} from "../Server/sifrr.server";
|
import {App} from "../Server/sifrr.server";
|
||||||
import {IoSocketController} from "_Controller/IoSocketController";
|
|
||||||
import {HttpRequest, HttpResponse} from "uWebSockets.js";
|
import {HttpRequest, HttpResponse} from "uWebSockets.js";
|
||||||
const register = require('prom-client').register;
|
const register = require('prom-client').register;
|
||||||
const collectDefaultMetrics = require('prom-client').collectDefaultMetrics;
|
const collectDefaultMetrics = require('prom-client').collectDefaultMetrics;
|
||||||
|
@ -152,7 +152,7 @@ export class GameRoom {
|
|||||||
closestItem.join(user);
|
closestItem.join(user);
|
||||||
} else {
|
} else {
|
||||||
const closestUser : User = closestItem;
|
const closestUser : User = closestItem;
|
||||||
const group: Group = new Group([
|
const group: Group = new Group(this.roomId,[
|
||||||
user,
|
user,
|
||||||
closestUser
|
closestUser
|
||||||
], this.connectCallback, this.disconnectCallback, this.positionNotifier);
|
], this.connectCallback, this.disconnectCallback, this.positionNotifier);
|
||||||
@ -200,7 +200,6 @@ export class GameRoom {
|
|||||||
if (group === undefined) {
|
if (group === undefined) {
|
||||||
throw new Error("The user is part of no group");
|
throw new Error("The user is part of no group");
|
||||||
}
|
}
|
||||||
const oldPosition = group.getPosition();
|
|
||||||
group.leave(user);
|
group.leave(user);
|
||||||
if (group.isEmpty()) {
|
if (group.isEmpty()) {
|
||||||
this.positionNotifier.leave(group);
|
this.positionNotifier.leave(group);
|
||||||
@ -209,6 +208,7 @@ export class GameRoom {
|
|||||||
throw new Error("Could not find group "+group.getId()+" referenced by user "+user.id+" in World.");
|
throw new Error("Could not find group "+group.getId()+" referenced by user "+user.id+" in World.");
|
||||||
}
|
}
|
||||||
this.groups.delete(group);
|
this.groups.delete(group);
|
||||||
|
//todo: is the group garbage collected?
|
||||||
} else {
|
} else {
|
||||||
group.updatePosition();
|
group.updatePosition();
|
||||||
//this.positionNotifier.updatePosition(group, group.getPosition(), oldPosition);
|
//this.positionNotifier.updatePosition(group, group.getPosition(), oldPosition);
|
||||||
|
@ -3,6 +3,7 @@ import { User } from "./User";
|
|||||||
import {PositionInterface} from "_Model/PositionInterface";
|
import {PositionInterface} from "_Model/PositionInterface";
|
||||||
import {Movable} from "_Model/Movable";
|
import {Movable} from "_Model/Movable";
|
||||||
import {PositionNotifier} from "_Model/PositionNotifier";
|
import {PositionNotifier} from "_Model/PositionNotifier";
|
||||||
|
import {gaugeManager} from "../Services/GaugeManager";
|
||||||
|
|
||||||
export class Group implements Movable {
|
export class Group implements Movable {
|
||||||
static readonly MAX_PER_GROUP = 4;
|
static readonly MAX_PER_GROUP = 4;
|
||||||
@ -13,12 +14,23 @@ export class Group implements Movable {
|
|||||||
private users: Set<User>;
|
private users: Set<User>;
|
||||||
private x!: number;
|
private x!: number;
|
||||||
private y!: number;
|
private y!: number;
|
||||||
|
private hasEditedGauge: boolean = false;
|
||||||
|
private wasDestroyed: boolean = false;
|
||||||
|
private roomId: string;
|
||||||
|
|
||||||
|
|
||||||
constructor(users: User[], private connectCallback: ConnectCallback, private disconnectCallback: DisconnectCallback, private positionNotifier: PositionNotifier) {
|
constructor(roomId: string, users: User[], private connectCallback: ConnectCallback, private disconnectCallback: DisconnectCallback, private positionNotifier: PositionNotifier) {
|
||||||
|
this.roomId = roomId;
|
||||||
this.users = new Set<User>();
|
this.users = new Set<User>();
|
||||||
this.id = Group.nextId;
|
this.id = Group.nextId;
|
||||||
Group.nextId++;
|
Group.nextId++;
|
||||||
|
//we only send a event for prometheus metrics if the group lives more than 5 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.wasDestroyed) {
|
||||||
|
this.hasEditedGauge = true;
|
||||||
|
gaugeManager.incNbGroupsPerRoomGauge(roomId);
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
users.forEach((user: User) => {
|
users.forEach((user: User) => {
|
||||||
this.join(user);
|
this.join(user);
|
||||||
@ -113,9 +125,11 @@ export class Group implements Movable {
|
|||||||
*/
|
*/
|
||||||
destroy(): void
|
destroy(): void
|
||||||
{
|
{
|
||||||
|
if (this.hasEditedGauge) gaugeManager.decNbGroupsPerRoomGauge(this.roomId);
|
||||||
for (const user of this.users) {
|
for (const user of this.users) {
|
||||||
this.leave(user);
|
this.leave(user);
|
||||||
}
|
}
|
||||||
|
this.wasDestroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
get getSize(){
|
get getSize(){
|
||||||
|
54
back/src/Services/GaugeManager.ts
Normal file
54
back/src/Services/GaugeManager.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import {Counter, Gauge} from "prom-client";
|
||||||
|
|
||||||
|
//this class should manage all the custom metrics used by prometheus
|
||||||
|
class GaugeManager {
|
||||||
|
private nbClientsGauge: Gauge<string>;
|
||||||
|
private nbClientsPerRoomGauge: Gauge<string>;
|
||||||
|
private nbGroupsPerRoomGauge: Gauge<string>;
|
||||||
|
private nbGroupsPerRoomCounter: Counter<string>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.nbClientsGauge = new Gauge({
|
||||||
|
name: 'workadventure_nb_sockets',
|
||||||
|
help: 'Number of connected sockets',
|
||||||
|
labelNames: [ ]
|
||||||
|
});
|
||||||
|
this.nbClientsPerRoomGauge = new Gauge({
|
||||||
|
name: 'workadventure_nb_clients_per_room',
|
||||||
|
help: 'Number of clients per room',
|
||||||
|
labelNames: [ 'room' ]
|
||||||
|
});
|
||||||
|
|
||||||
|
this.nbGroupsPerRoomCounter = new Counter({
|
||||||
|
name: 'workadventure_counter_groups_per_room',
|
||||||
|
help: 'Counter of groups per room',
|
||||||
|
labelNames: [ 'room' ]
|
||||||
|
});
|
||||||
|
this.nbGroupsPerRoomGauge = new Gauge({
|
||||||
|
name: 'workadventure_nb_groups_per_room',
|
||||||
|
help: 'Number of groups per room',
|
||||||
|
labelNames: [ 'room' ]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
incNbClientPerRoomGauge(roomId: string): void {
|
||||||
|
this.nbClientsGauge.inc();
|
||||||
|
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
||||||
|
}
|
||||||
|
|
||||||
|
decNbClientPerRoomGauge(roomId: string): void {
|
||||||
|
this.nbClientsGauge.dec();
|
||||||
|
this.nbClientsPerRoomGauge.dec({ room: roomId });
|
||||||
|
}
|
||||||
|
|
||||||
|
incNbGroupsPerRoomGauge(roomId: string): void {
|
||||||
|
this.nbGroupsPerRoomCounter.inc({ room: roomId })
|
||||||
|
this.nbGroupsPerRoomGauge.inc({ room: roomId })
|
||||||
|
}
|
||||||
|
|
||||||
|
decNbGroupsPerRoomGauge(roomId: string): void {
|
||||||
|
this.nbGroupsPerRoomGauge.dec({ room: roomId })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const gaugeManager = new GaugeManager();
|
@ -23,7 +23,6 @@ import {
|
|||||||
WebRtcStartMessage,
|
WebRtcStartMessage,
|
||||||
QueryJitsiJwtMessage,
|
QueryJitsiJwtMessage,
|
||||||
SendJitsiJwtMessage,
|
SendJitsiJwtMessage,
|
||||||
CharacterLayerMessage,
|
|
||||||
SendUserMessage
|
SendUserMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
import {PointInterface} from "../Model/Websocket/PointInterface";
|
||||||
@ -37,11 +36,11 @@ import {Movable} from "../Model/Movable";
|
|||||||
import {PositionInterface} from "../Model/PositionInterface";
|
import {PositionInterface} from "../Model/PositionInterface";
|
||||||
import {adminApi, CharacterTexture} from "./AdminApi";
|
import {adminApi, CharacterTexture} from "./AdminApi";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {Gauge} from "prom-client";
|
|
||||||
import {emitError, emitInBatch} from "./IoSocketHelpers";
|
import {emitError, emitInBatch} from "./IoSocketHelpers";
|
||||||
import Jwt from "jsonwebtoken";
|
import Jwt from "jsonwebtoken";
|
||||||
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
||||||
import {clientEventsEmitter} from "./ClientEventsEmitter";
|
import {clientEventsEmitter} from "./ClientEventsEmitter";
|
||||||
|
import {gaugeManager} from "./GaugeManager";
|
||||||
|
|
||||||
interface AdminSocketRoomsList {
|
interface AdminSocketRoomsList {
|
||||||
[index: string]: number;
|
[index: string]: number;
|
||||||
@ -58,30 +57,13 @@ export interface AdminSocketData {
|
|||||||
export class SocketManager {
|
export class SocketManager {
|
||||||
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
||||||
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
||||||
private nbClientsGauge: Gauge<string>;
|
|
||||||
private nbClientsPerRoomGauge: Gauge<string>;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.nbClientsGauge = new Gauge({
|
clientEventsEmitter.registerToClientJoin((clientUUid: string, roomId: string) => {
|
||||||
name: 'workadventure_nb_sockets',
|
gaugeManager.incNbClientPerRoomGauge(roomId);
|
||||||
help: 'Number of connected sockets',
|
|
||||||
labelNames: [ ]
|
|
||||||
});
|
});
|
||||||
this.nbClientsPerRoomGauge = new Gauge({
|
clientEventsEmitter.registerToClientLeave((clientUUid: string, roomId: string) => {
|
||||||
name: 'workadventure_nb_clients_per_room',
|
gaugeManager.decNbClientPerRoomGauge(roomId);
|
||||||
help: 'Number of clients per room',
|
|
||||||
labelNames: [ 'room' ]
|
|
||||||
});
|
|
||||||
|
|
||||||
clientEventsEmitter.registerToClientJoin((clientUUid, roomId) => {
|
|
||||||
this.nbClientsGauge.inc();
|
|
||||||
// Let's log server load when a user joins
|
|
||||||
console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
|
|
||||||
});
|
|
||||||
clientEventsEmitter.registerToClientLeave((clientUUid, roomId) => {
|
|
||||||
this.nbClientsGauge.dec();
|
|
||||||
// Let's log server load when a user leaves
|
|
||||||
console.log('A user left (', this.sockets.size, ' connected users)');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +89,6 @@ export class SocketManager {
|
|||||||
const viewport = client.viewport;
|
const viewport = client.viewport;
|
||||||
try {
|
try {
|
||||||
this.sockets.set(client.userId, client); //todo: should this be at the end of the function?
|
this.sockets.set(client.userId, client); //todo: should this be at the end of the function?
|
||||||
clientEventsEmitter.emitClientJoin(client.userUuid, client.roomId);
|
|
||||||
//join new previous room
|
//join new previous room
|
||||||
const gameRoom = this.joinRoom(client, position);
|
const gameRoom = this.joinRoom(client, position);
|
||||||
|
|
||||||
@ -377,8 +358,8 @@ export class SocketManager {
|
|||||||
} finally {
|
} finally {
|
||||||
//delete Client.roomId;
|
//delete Client.roomId;
|
||||||
this.sockets.delete(Client.userId);
|
this.sockets.delete(Client.userId);
|
||||||
this.nbClientsPerRoomGauge.dec({ room: Client.roomId });
|
|
||||||
clientEventsEmitter.emitClientLeave(Client.userUuid, Client.roomId);
|
clientEventsEmitter.emitClientLeave(Client.userUuid, Client.roomId);
|
||||||
|
console.log('A user left (', this.sockets.size, ' connected users)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -410,8 +391,6 @@ export class SocketManager {
|
|||||||
private joinRoom(client : ExSocketInterface, position: PointInterface): GameRoom {
|
private joinRoom(client : ExSocketInterface, position: PointInterface): GameRoom {
|
||||||
|
|
||||||
const roomId = client.roomId;
|
const roomId = client.roomId;
|
||||||
//join user in room
|
|
||||||
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
|
||||||
client.position = position;
|
client.position = position;
|
||||||
|
|
||||||
const world = this.Worlds.get(roomId)
|
const world = this.Worlds.get(roomId)
|
||||||
@ -425,6 +404,8 @@ export class SocketManager {
|
|||||||
});
|
});
|
||||||
//join world
|
//join world
|
||||||
world.join(client, client.position);
|
world.join(client, client.position);
|
||||||
|
clientEventsEmitter.emitClientJoin(client.userUuid, client.roomId);
|
||||||
|
console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user