Javascript-форум (https://javascript.ru/forum/)
-   Node.JS (https://javascript.ru/forum/node-js-io-js/)
-   -   GET запросы становятся в очередь. (https://javascript.ru/forum/node-js-io-js/83602-get-zaprosy-stanovyatsya-v-ochered.html)

Oleg_Lugaro 21.01.2022 15:23

GET запросы становятся в очередь.
 
Пример учебный. Пытаюсь понять.

1) Я получаю get запрос start1 и запускаю асинхронную функцию (в примере вызов скрипт питона, там просто таймер на 6 сек).
2) Не дожидаясь эти 6 сек отправляю еще раз этот запрос с другой вкладки браузера.
3) Ожидаю что запуск скрипта произойдет параллельно (ну или будет системная ошибка что файл занят), но в итоге второй get запрос выполняется только после того как выполнился первый get запрос.



Но при этом я могу послать одновременно запросы start1 и start2, которые параллельно будут выполнять эту асинхронную функцию не дожидаясь друг друга.



То есть из этого следует что если один клиент отправил GET запрос
с длительностью ответа 6 сек , другой клиент отправивший такой же GET будет ждать это время, даже если ядро и память сервера не загружены?

Я уже применял масштабирование с помощью cluster, но это это же для того что бы занять неиспользуемые ядра процессора.
А что делать что бы один клиент не ждал другого при выполнении для него асинхронной функции?

//express, cors и ssl
let fs = require('fs');
var express = require('express')
var app = express()
const cors = require('cors');
const https = require('https').createServer({
    key: fs.readFileSync('./config/ssl/owen.pem'),
    cert: fs.readFileSync('./config/ssl/owen.crt'),
  }, app);

app.use(cors());

//для запуска скрипта питона в корором таймер на 6 сек
const util = require('util');
const exec = util.promisify(require('child_process').exec);


app.get('/start1', function (req, res) { 
    my_test()
     .then((e) => {res.send('test1 завершил работу')})
})

app.get('/start2', function (req, res) { 
    my_test()
     .then((e) => {res.send('test2 завершил работу')});

});
let i = 1;
async function my_test(){
    let number = i;
    i++;
    console.log('старт скрипта ' + number);
    const { stdout, stderr } = await exec('/usr/bin/python3 /home/omosencev/temp/test1.py >> test1.log 2>&1');
    console.log('конец скрипта ' + number);
    return
}


https.listen(3011, function () {
    console.log('тестовый PORT', 3011)
})

ksa 21.01.2022 15:42

Цитата:

Сообщение от Oleg_Lugaro
А что делать что бы один клиент не ждал другого при выполнении для него асинхронной функции?

Ну у тебя там async/await... Т.ч. асинхронность у тебя ну очень условная.

Но пример меня заинтересовал. Если будет время - потестю его на именно асинхронных запросах.
Поскольку поведение при start1+start1 меня удивило.

Oleg_Lugaro 21.01.2022 16:05

Цитата:

Сообщение от ksa (Сообщение 543171)
Ну у тебя там async/await... Т.ч. асинхронность у тебя ну очень условная.

Но пример меня заинтересовал. Если будет время - потестю его на именно асинхронных запросах.
Поскольку поведение при start1+start1 меня удивило.

Разве условная? Я добавил логи после then, и они срабатывают не дожидаясь выполнения моей асинхронной функции.


ksa 21.01.2022 16:09

Сделал такой пример для теста...
const app = require('express')()

const host = '127.0.0.1'
const port = 7000

app.get('/start1', (req, res) => {
	test()
		.then(_ => res.send('test1 завершил работу'))
})

app.get('/start2', (req, res) => {
	test()
		.then(_ => res.send('test2 завершил работу'))
})

app.use((req, res, next) => {
  res.status(404).type('text/plain')
  res.send('Not found')
})

app.listen(port, host, function () {
  console.log(`Server listens http://${host}:${port}`)
})
let i = 0
function test() {
	return new Promise((resolve, reject) => {
		const number = ++i
		console.log('старт скрипта ' + number)
		setTimeout(_ => {
			console.log('конец скрипта ' + number)
			resolve()
		}, 6000)
	})
}

Все повторилось как и в твоем варианте... :yes:
Если стартовать start1+start1, сообщения выводятся так
старт скрипта 1
конец скрипта 1
старт скрипта 2
конец скрипта 2

Т.е. пока не получит ответ первый запрос, вторая обработка стартовать не станет.

Если стартовать start1+start2, сообщения выводятся
старт скрипта 3
старт скрипта 4
конец скрипта 3
конец скрипта 4

ksa 21.01.2022 16:16

Немного добавил инфы по тесту...
const app = require('express')()

const host = '127.0.0.1'
const port = 7000

let s1 = 0
app.get('/start1', (req, res) => {
	const number = ++s1
	console.log('Запрос start1 ' + number)
	test()
		.then(_ => res.send('test1 завершил работу'))
})

let s2 = 0
app.get('/start2', (req, res) => {
	const number = ++s2
	console.log('Запрос start2 ' + number)
	test()
		.then(_ => res.send('test2 завершил работу'))
})

app.use((req, res, next) => {
  res.status(404).type('text/plain')
  res.send('Not found')
})

app.listen(port, host, function () {
  console.log(`Server listens http://${host}:${port}`)
})
let i = 0
function test() {
	return new Promise((resolve, reject) => {
		const number = ++i
		console.log('старт скрипта ' + number)
		setTimeout(_ => {
			console.log('конец скрипта ' + number)
			resolve()
		}, 6000)
	})
}

Вывод сообщений...
Запрос start1 1
старт скрипта 1
конец скрипта 1
Запрос start1 2
старт скрипта 2
конец скрипта 2
Запрос start1 3
старт скрипта 3
Запрос start2 1
старт скрипта 4
конец скрипта 3
конец скрипта 4

Т.е. даже обработка запроса не "освобождается" пока не даст ответ на первый запрос...

ksa 21.01.2022 16:19

Цитата:

Сообщение от Oleg_Lugaro
Я добавил логи после then, и они срабатывают не дожидаясь выполнения моей асинхронной функции

Ты сделай логи в async/await... ;)

ksa 21.01.2022 16:22

Цитата:

Сообщение от ksa
Немного добавил инфы по тесту...

package.json, если кто будет пробовать...
{
  "name": "tmp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.2"
  }
}

Oleg_Lugaro 21.01.2022 16:53

Цитата:

Сообщение от ksa (Сообщение 543175)
Ты сделай логи в async/await... ;)

Ну для самого запроса она должна же выглядить как промис. Если сделать console.log(my_test()) в консоли будет промис.

Ну ладно. Я сделал без промисов и асинк: результат тот же... Наблюдаю что запросы обрабатываться последовательно по очереди.



//express, cors и ssl
let fs = require('fs');
var express = require('express')
var app = express()
const cors = require('cors');
const https = require('https').createServer({
    key: fs.readFileSync('./config/ssl/owen.pem'),
    cert: fs.readFileSync('./config/ssl/owen.crt'),
  }, app);

app.use(cors());

//для запуска скрипта питона в корором таймер на 6 сек
const { exec } = require('child_process');


app.get('/start1', function (req, res) { 
    my_test(res, '1')
    console.log('21 сточка');
})

app.get('/start2', function (req, res) { 
    my_test(res, '2')
    console.log('27 сточка');
});


function my_test(res, i){
    console.log(`старт скрипта test${i}`);
    exec('/usr/bin/python3 /home/omosencev/temp/test1.py >> test1.log 2>&1', (error, stdout, stderr) => {
        if (error) {
          res.send(error);
          return;
        }
        console.log(`test${i} завершил работу`);
        res.send(`test${i} завершил работу`)}
        );
    return
}


https.listen(3011, function () {
    console.log('тестовый PORT', 3011)
})

Oleg_Lugaro 21.01.2022 16:56

Цитата:

Сообщение от ksa (Сообщение 543174)
Т.е. даже обработка запроса не "освобождается" пока не даст ответ на первый запрос...

Вот это и интересно. Причем другие запросы свободны.

ksa 21.01.2022 17:34

Цитата:

Сообщение от Oleg_Lugaro
Причем другие запросы свободны.

Ну они же "другие"... :D
Видно другой обработчик "свободен", потому и принимает запрос.


Часовой пояс GMT +3, время: 23:55.