ECONNRESET в Express.js (Node.js) с несколькими запросами - PullRequest
0 голосов
/ 16 ноября 2018

При стандартной настройке Express.js

const express = require('express');
const app = express();
const router = express.Router();

router.get('/test/:id', (req, res) => {
  return res.status(200).json({ hello: 'world' });
});

app.use('/api', router);

app.listen(3000, () => console.info('Up on port 3000));

Я делаю 1000 запросов к конечной точке, один за другим:

const fetch = require('node-fetch');
for (let i = 0; i < 1000; i++) {
  let id = Math.floor(Math.random() * 12) + 1;
  fetch(`http://localhost:3000/api/test/${id}`).then(res => res.json()).then(data => console.log(data)).catch(error => console.error(error));
}

Однако я вижу возвращенные данные,время от времени я вижу ошибку ECONNRESET.Количество ECONNRESET сообщений об ошибках также варьируется: иногда я получаю несколько, иногда намного больше.Я понимаю сообщение, но не могу решить, что за ним стоит.

Вот пример ошибки:

{ FetchError: request to http://localhost:3000/api/test/8 failed, reason: connect ECONNRESET 127.0.0.1:3000
    at ClientRequest.<anonymous> (node_modules/node-fetch/lib/index.js:1345:11)
    at ClientRequest.emit (events.js:182:13)
    at Socket.socketErrorListener (_http_client.js:399:9)
    at Socket.emit (events.js:182:13)
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process.internalTickCallback (internal/process/next_tick.js:72:19)
  message:
   'request to http://localhost:3000/api/departments/8 failed, reason: connect ECONNRESET 127.0.0.1:3000',
  type: 'system',
  errno: 'ECONNRESET',
  code: 'ECONNRESET' }

Обратите внимание, что я попытался сделать запрос, используяAxios, встроенный модуль HTTP все, чтобы помочь.Я уверен, что проблема связана с тем, что мое приложение Express обрабатывает запрос, но не уверен, как именно это исправить.

Обновление 1:

Согласно предложению в комментарии, вот асинхронная версия:

async function f() {
  const array = Array.from(Array(1000).keys());
  for (const el of array) {
    try {
      let id = Math.floor(Math.random() * 12) + 1;
      const result = await fetch(`http://localhost:3000/api/test/${id}`).then(res => res.json());
      console.log(result);
      return result;
    } catch(e) {
      console.log(e);
    }
  }
}

f();

Теперь я получаю случайные ECONNREFUSED сообщения.

Обновление 2:

Основываясь на ответе Mazki516, вот решение, которое работает:

// previous require statements
const cluster = require('cluster');
const os = require('os');

if (cluster.isMaster) {
  const cpuCount = os.cpus().length
  for (let i = 0; i < cpuCount; i++) {
      cluster.fork()
  }
} else {
  const app = express();
  // rest of the route definitions
  // also app.listen() etc...
}
cluster.on('exit', worker => {
  console.log(`${worker.id} removed`);
  cluster.fork();
});

1 Ответ

0 голосов
/ 16 ноября 2018

Одна из причин, по которой вы это видите, заключается в том, что вы делаете вызовы «параллельно». Вы начинаете вызовы один за другим, но циклы завершатся, вероятно, до того, как первые результаты вернутся с сервера. Цикл продолжается до конца, и стек вызовов заполняется 1000 асинхронных запросов к серверу.

Вы нарушаете аппаратные / программные ограничения, и с кодом все в порядке. если бы вы захотели создать сервер, который мог бы одновременно обрабатывать 1 тыс. (и многие другие) запросы, я бы заглянул в «кластерный» модуль узла.

Обратите внимание, что при выполнении сетевых операций между серверами допустимо использование ограничения параллелизма. (например: до 4 запросов одновременно)

но вы всегда можете масштабировать свой сервер за пределы одной машины и обрабатывать гораздо больше трафика.

...