Тайм-аут node.js перезапускает вызов API - PullRequest
0 голосов
/ 04 февраля 2019

Платформа:

У меня есть API в sails.js и интерфейс в реагирует .Вызовы между передней и задней панелями выполняются с помощью fetch api .

Дополнительная информация:

В ходе некоторых конечных точек API, которые я имеючтобы выполнить внешний файл, на этом этапе я использую функцию execfile () из node.js , и мне приходится ждать, пока он будет выполнен, чтобы ответить на внешний интерфейс.

В чем проблема?

Если файл выполняется за короткое время, например, менее 1 минуты, все работает хорошо, и поведение происходит так, как ожидается на обоихсторон, но если (в этом случае) выполнение файла занимает более 1 минуты, есть что-то, чтобы вызвать второй вызов api (я не знаю, где это вызывается, но я тестировал ту же конечную точку с почтальон и у меня не было этой проблемы, поэтому я подозреваю, что реагирует / fetch-api) , и вызов API с теми же данными из первого вызова повторяется.Это приводит к тому, что файл запускается дважды.

Еще более странным является то, что если у вас включен сетевой инспектор DevTools, этот второй вызов не появляется, но ничто в документации по sailjs не указывает на такое поведение.

Пример конечной точки в sails.js:

/**
 * FooController
 */
const execFile = require("child_process").execFile;
module.exports = {
  foo: async (req, res) => {
    let result = await module.exports._executeScript(req.body).catch(() => {
      res.status(500).json({ error: "something has occurred" });
    });
    res.json(result);
  },
  _executeScript: body => {
    return new Promise((resolve, reject) => {
      let args = [process.cwd() + "/scripts/" + "myExternalFile.js", body];
      let elem = await module.exports
        ._execScript(args)
        .catch(err => reject(err));
      resolve(elem);
    });
  },
  _execScript: args => {
    return new Promise((resolve, reject) => {
      try {
        execFile("node", args, { timeout: 150000 }, (error, stdout, stderr) => {
          if (error || (stderr != null && stderr !== "")) {
            console.error(error);
          } else {
            console.log(stdout);
          }
          let output = { stdout: stdout, stderr: stderr };
          resolve(output);
        });
      } catch (err) {
        reject(err);
      }
    });
  }
};

Пример реакции компонента на вызов fetch:

import React from "react";
import { notification } from "antd";
import "./../App.css";
import Oauth from "./../helper/Oauth";
import Config from "./../config.json";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      syncInAction: false,
      data: null
    };
  }
  componentDidMount() {
    this.handleSync();
  }
  async handleSync() {
    let response = await fetch(Config.apiLink + "/foo/foo", {
      method: "POST",
      mode: "cors",
      headers: {
        Authorization: Oauth.isLoggedIn(),
        Accept: "application/json",
        "Content-Type": "application/json"
      },
      body: JSON.stringify(this.state.myData)
    }).catch(err => {
      notification.error({
        key: "catch-ApiFail",
        message: "Erro"
      });
    });

    let json = await response.json();
    this.setState({
      syncInAction: false,
      data: json
    });
  }
  render() {
    return <div>{this.state.data}</div>;
  }
}

export default App;

Какова моя ожидаемая цель / поведение:

Не имеет значения, если вызов занимает 1 минуту или 10 часов, файл может быть вызван только один раз и когда он завершится, тогда да, он может вернуться к веб-интерфейсу.

Обратите внимание, что примеры не имеют исходного кода и не были протестированы.Это упрощенная версия кода для объяснения поведения

1 Ответ

0 голосов
/ 04 февраля 2019

Я решил проблему, по-видимому, nodejs имеет время по умолчанию 2 минуты на сервере и может быть переписано, чтобы пропустить этот тайм-аут или увеличить его.Это было просто добавление строки кода в начале конечной точки foo (), и проблема была решена.

Поведение повторного вызова состоит в том, что он не задокументирован, и странно не иметь этогоповедение при использовании почтальона, но вот решение для тех, кто в этом нуждается.

Конечный результат:

foo: async (req, res) => {
  req.setTimeout(0);
  let result = await module.exports._executeScript(req.body).catch(() => {
    res.status(500).json({ error: "something has occurred" });
  });
  res.json(result);
};
...