Sets quiz to inactive if no clients are consuming the quiz exchange for more than 60 seconds

parent 2a8a6143
import { ObjectId } from 'bson';
import * as http from 'http';
import * as https from 'https';
import { DeleteWriteOpResultObject } from 'mongodb';
import AMQPConnector from '../../db/AMQPConnector';
import DbDAO from '../../db/DbDAO';
......@@ -10,6 +12,7 @@ import { QuizState } from '../../enums/QuizState';
import { QuizVisibility } from '../../enums/QuizVisibility';
import { IQuizEntity, IQuizSerialized } from '../../interfaces/quizzes/IQuizEntity';
import { ISessionConfigurationEntity } from '../../interfaces/session_configuration/ISessionConfigurationEntity';
import { settings } from '../../statistics';
import { AbstractEntity } from '../AbstractEntity';
import { MemberEntity } from '../member/MemberEntity';
import { MemberGroupEntity } from '../member/MemberGroupEntity';
......@@ -138,7 +141,11 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
this._description = value;
}
private _dropEmptyQuizTimeout: any;
private _dropEmptyQuizSettings = {
interval: 30000,
intervalInstance: null,
isEmpty: false,
};
private _quizTimerInterval: any;
private _quizTimer: number;
......@@ -160,6 +167,25 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
this._visibility = quiz.visibility;
this._description = quiz.description;
this._exchangeName = encodeURI(`quiz_${quiz.name}`);
this._dropEmptyQuizSettings.intervalInstance = setInterval(() => {
this.checkExistingConnection();
}, this._dropEmptyQuizSettings.interval);
}
public setInactive(): void {
clearInterval(this._dropEmptyQuizSettings.intervalInstance);
DbDAO.updateOne(DbCollection.Quizzes, { _id: this.id }, { state: QuizState.Inactive });
DbDAO.deleteMany(DbCollection.Members, { currentQuizName: this.name });
AMQPConnector.channel.publish('global', '.*', Buffer.from(JSON.stringify({
status: StatusProtocol.Success,
step: MessageProtocol.SetInactive,
payload: {
quizName: this.name,
},
})));
}
public async onMemberAdded(member: MemberEntity): Promise<void> {
......@@ -344,4 +370,46 @@ export class QuizEntity extends AbstractEntity implements IQuizEntity {
}
}
}
private checkExistingConnection(): void {
const reqOptions: http.RequestOptions = {
protocol: settings.amqp.managementApi.protocol,
host: settings.amqp.managementApi.host,
port: settings.amqp.managementApi.port,
path: `/api/exchanges/${encodeURIComponent(settings.amqp.vhost)}/quiz_${encodeURIComponent(encodeURIComponent(this.name))}/bindings/source`,
auth: `${settings.amqp.managementApi.user}:${settings.amqp.managementApi.password}`,
};
(settings.amqp.managementApi.host.startsWith('https') ? https : http).get(reqOptions, response => {
let data = '';
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', () => {
const parsedData = JSON.parse(data);
if (Array.isArray(parsedData) && parsedData.length) {
this._dropEmptyQuizSettings.isEmpty = false;
return;
}
if (this._dropEmptyQuizSettings.isEmpty) {
this.setInactive();
return;
}
this._dropEmptyQuizSettings.isEmpty = true;
});
response.on('error', () => {
if (this._dropEmptyQuizSettings.isEmpty) {
this.setInactive();
return;
}
this._dropEmptyQuizSettings.isEmpty = true;
});
});
}
}
......@@ -37,6 +37,8 @@ export interface IQuizEntity extends IQuizBase {
stop(): void;
setInactive(): void;
onRemove(): void;
onMemberAdded(member: MemberEntity): Promise<void>;
......
......@@ -577,16 +577,7 @@ export class QuizRouter extends AbstractRouter {
return;
}
DbDAO.updateOne(DbCollection.Quizzes, { _id: quiz.id }, { state: QuizState.Inactive });
DbDAO.deleteMany(DbCollection.Members, { currentQuizName: quiz.name });
AMQPConnector.channel.publish('global', '.*', Buffer.from(JSON.stringify({
status: StatusProtocol.Success,
step: MessageProtocol.SetInactive,
payload: {
quizName,
},
})));
quiz.setInactive();
return {
status: StatusProtocol.Success,
......
......@@ -26,6 +26,11 @@ const amqpHostname = process.env.AMQP_HOSTNAME || 'localhost';
const amqpVhost = process.env.AMQP_VHOST || '/';
const amqpUser = process.env.AMQP_USER || 'guest';
const amqpPassword = process.env.AMQP_PASSWORD || 'guest';
const amqpManagementApiProtocol = process.env.AMQP_MANAGEMENT_API_PROTOCOL || 'http:';
const amqpManagementApiHost = process.env.AMQP_MANAGEMENT_API_HOST || 'localhost';
const amqpManagementApiPort = process.env.AMQP_MANAGEMENT_API_PORT || '15672';
const amqpManagementUser = process.env.AMQP_MANAGEMENT_USER || amqpUser;
const amqpManagementPassword = process.env.AMQP_MANAGEMENT_PASSWORD || amqpPassword;
export const staticStatistics = {
appName: 'arsnova-click-v2-backend',
......@@ -65,6 +70,13 @@ export const settings = {
vhost: amqpVhost,
user: amqpUser,
password: amqpPassword,
managementApi: {
host: amqpManagementApiHost,
protocol: amqpManagementApiProtocol,
port: amqpManagementApiPort,
user: amqpManagementUser,
password: amqpManagementPassword,
},
},
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment