serveur http buffer toutes les requetes envois de les executer
Bonjour,
J'ai développé un serveur avec le package http. Il doit répondre à des requêtes de client en gérant une DB postgreSQL (insert, select, ...).
J'ai fait un script de test qui lui envoie 10 000 requêtes (avec le package 'request') mais je penses que je n'arrive pas à mettre en place le côté asynchrone (autant client que serveur).
Je bute depuis plusieurs jours sur ce problème. Voilà les différentes étapes réalisée actuellement :
Le serveur fonctionne en deux étapes:
- first : des logs sur la console script test : envoie des requetes
- puis : des logs sur la console serveur : quant le script de test à tout envoyé, le les réceptionne TOUTES (le serveur s’exécute jusqu’à repos/roles.js ligne 27, puis handle la prochaine requête)
- puis : des logs sur la console serveur et script test : le serveur execute chaque insert (call la fonction de pg-promise) puis envoie les résultats a chaque fois, et en parallèle le script test affiche le retour sur la console
Est-ce un fonctionnement normal ? N'y a-t-il pas moyen que le serveur receptionne les requete au fur et a mesure que le script de test les envoies ? C'est-à-dire avoir quelque chose comme :
- first : des logs sur la console de test et serveur : envoie des requêtes par le test, réception des requêtes par le serveur au fur et a mesure
- puis : des logs sur la console serveur et de test : le serveur continu de recevoir au fur et a mesure que le test envoie et en plus fait des inserts et renvoie les données dès qu'il peut ?
J'ai trouvé cette vidéo et si j'ai bien compris comment fonctionne l'asynchronisme (avec l'event loop) sur JS je penses que ce n'est pas possible.. Quelqu'un peut-il me confirmer ? Elle date de 2014, ce qui y ai dit est toujours valable ?
https://www.youtube.com/watch?v=8aGhZQkoFbQ
Un peu de code :
Script de test :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| const request = require('request');
function concurrentRequests(){
for (var count = 1; count <= 10000; count++) {
let roleStatement = {
jsonrpc: '2.0',
host: 'test',
id: count,
method: "roles.insert",
params: {
return: true,
data: { name: count.toString() }
}
};
ContactApi(roleStatement)
.then((result) => { Logger(`${JSON.stringify(result)}`); })
.catch((ex) => { Logger(`ERROR ${roleStatement.id} : ${ex.message}`)});
}
}
function ContactApi(statement) {
return new Promise(function(resolve, reject) {
Logger(`Prepare request for ${statement.method}(${statement.id})...`)
request.post({
url:'http://localhost:9000/api/v1',
json: statement
}, function(err,httpResponse,body){
if(err) {
reject(err);
}
else {
resolve(body);
}
});
});
}
function Logger(message) {
const Timer = new Date();
console.log(`${Timer} : ${JSON.stringify(message)}`);
}
concurrentRequests(); |
(main) server.js :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| const http = require('http');
const Database = require('../db'); // ./db/index.js
const path = '/api/v1', port = 9000;
const methods = Database.methods;
/* hidden for brevity */
function sendResponse(res, response) {
if (response) {
const responseStr = JSON.stringify(response);
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Length', responseStr.length);
res.write(responseStr);
} else {
// Respond 204 for notifications with no response
res.setHeader('Content-Length', 0);
res.statusCode = 204;
}
res.end();
}
const requestHandler = (req, res) => {
// lecture requete
const body = [];
req.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
const bodyStr = Buffer.concat(body).toString();
res.setHeader('Content-Type', 'application/json');
// parse body en JSON
let request;
try {
request = JSON.parse(bodyStr);
} catch (err) {
const response = {
id: null,
jsonrpc: '2.0',
error: {
code: 'consts.PARSE_ERROR',
message: err.message,
},
};
sendResponse(res, response);
return;
}
requestProcessor(request).then((response) => {
sendResponse(res, response);
});
});
}
async function requestProcessor(request) {
let response = {
id: request.id,
host: request.host,
jsonrpc: '2.0',
};
try {
response.result = await Promise.resolve(methods[request.method](request.params));
if (!response.id) {
response = undefined; // don't return a response if id is null
}
}
catch (err) {
/* hidden for brevity */
}
return response;
}
const server = http.createServer(requestHandler);
server.listen(port, (err) => {
if(err) {
return console.log('something bad happened', err);
}
console.log((`server is listening on ${port}`);
}) |
un des repo (roles.js):
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| 'use strict';
const cs = {}; // Reusable ColumnSet objects.
var Collections = {};
class RolesRepository {
constructor(db, pgp) {
this.db = db;
this.pgp = pgp;
// set-up all ColumnSet objects, if needed:
this.Collections = createColumnsets(pgp);
this.methods = {
'roles.insert': this.add.bind(this)
}
}
async add(params) {
var query = this.pgp.helpers.insert(params.data, this.Collections.insert);
if(params.return) query += " RETURNING *";
Log(`inserting role ${JSON.stringify(params)}`);
return this.db.any(query)
.then(data => {
Log(`INSERTED role ${JSON.stringify(data)}`);
return data;
})
.catch(ex => {
throw new Error(ex);
});
}
}
/* hidden for brevity */
module.exports = RolesRepository; |