使用外部时间限制在 Node/Express 中链接异步等待调用
Chaining async await calls in Node/Express with an external time limit
我正在构建一个调用 Express 应用程序的 Slackbot,然后需要 1) 从 Slack API 获取一些其他数据,以及 2) 将结果数据插入我的数据库。我想我最终使用 async await
的流程是正确的,但是操作超时,因为来自 Slackbot 的原始调用需要在我无法控制的某个固定时间内收到响应。就我的目的而言,立即通过响应 ping 机器人,然后异步执行其余逻辑就可以了。但我想知道设置它的最佳方法。
我的 Express 路线如下:
const express = require('express');
const router = express.Router();
const knex = require('../../db/knex.js');
const slack = require('../../services/slack_helpers');
// POST api/slack/foo
router.post('/foo', async (req, res) => {
let [body, images] = await slack.grab_context(req);
knex('texts')
.insert({ body: body,
image_ids: images })
.then(text => { res.send('worked!'); }) // This sends a response back to the original Slackbot call
.catch(err => { res.send(err); })
});
module.exports = router;
然后 slack_helpers
模块看起来像:
const { WebClient } = require('@slack/web-api');
const Slack = new WebClient(process.env.SLACKBOT_TOKEN);
async function grab_context(req) {
try {
const context = await Slack.conversations.history({ // This is the part that takes too long
channel: req.body.channel_id,
latest: req.headers['X-Slack-Request-Timestamp'],
inclusive: true,
limit: 5
});
} catch (error) {
return [error.toString(), 'error'];
}
return await parse_context(context);
};
function parse_context(context) {
var body = [];
context.messages.forEach(message => {
body.push(message.text);
});
body = body.join(' \n');
return [body, ''];
}
module.exports = {
grab_context
};
我仍然在研究异步编程,所以我可能遗漏了一些明显的东西。我认为基本上 res.send
之类的东西可能需要在 grab_context
调用之前出现?但同样,不确定这里的最佳流量。
更新
我也在 API 路由中尝试过这种模式,但仍然超时:
slack.grab_context(req).then((body, images) => {
knex ...
})
你的超时可能不是你想的那样。据我所知,它来自 grab_context
。考虑以下 grab_context
的简化版本
async function grab_context_simple() {
try {
const context = { hello: 'world' }
} catch (error) {
return [error.toString(), 'error']
}
return context
}
grab_context_simple() /* => Promise {
<rejected> ReferenceError: context is not defined
...
} */
您正在尝试 return context
在定义它的 try 块之外,因此 grab_context
将以 ReferenceError
拒绝。很可能这个错误此刻正在被吞噬,所以它看起来像是超时了。
修复方法是在 grab_context
中移动一行
async function grab_context(req) {
try {
const context = await Slack.conversations.history({
channel: req.body.channel_id,
latest: req.headers['X-Slack-Request-Timestamp'],
inclusive: true,
limit: 5
});
return await parse_context(context); // <- moved this
} catch (error) {
return [error.toString(), 'error'];
}
};
I'm wondering the best way to set this up.
您可以添加更高级别的 try/catch
块来处理由 /foo
路由引起的错误。您还可以通过在 async/await 和承诺链之间保持一致来提高可读性。下面是如何将 async/await 与 knex
以及前面提到的 try/catch
块
一起使用
const express = require('express');
const router = express.Router();
const knex = require('../../db/knex.js');
const slack = require('../../services/slack_helpers');
const insertInto = table => payload => knex(table).insert(payload)
const onFooRequest = async (req, res) => {
try {
let [body, images] = await slack.grab_context(req);
const text = await insertInto('texts')({
body: body,
image_ids: images,
});
res.send('worked!');
} catch (err) {
res.send(err);
}
}
router.post('/foo', onFooRequest);
module.exports = router;
我正在构建一个调用 Express 应用程序的 Slackbot,然后需要 1) 从 Slack API 获取一些其他数据,以及 2) 将结果数据插入我的数据库。我想我最终使用 async await
的流程是正确的,但是操作超时,因为来自 Slackbot 的原始调用需要在我无法控制的某个固定时间内收到响应。就我的目的而言,立即通过响应 ping 机器人,然后异步执行其余逻辑就可以了。但我想知道设置它的最佳方法。
我的 Express 路线如下:
const express = require('express');
const router = express.Router();
const knex = require('../../db/knex.js');
const slack = require('../../services/slack_helpers');
// POST api/slack/foo
router.post('/foo', async (req, res) => {
let [body, images] = await slack.grab_context(req);
knex('texts')
.insert({ body: body,
image_ids: images })
.then(text => { res.send('worked!'); }) // This sends a response back to the original Slackbot call
.catch(err => { res.send(err); })
});
module.exports = router;
然后 slack_helpers
模块看起来像:
const { WebClient } = require('@slack/web-api');
const Slack = new WebClient(process.env.SLACKBOT_TOKEN);
async function grab_context(req) {
try {
const context = await Slack.conversations.history({ // This is the part that takes too long
channel: req.body.channel_id,
latest: req.headers['X-Slack-Request-Timestamp'],
inclusive: true,
limit: 5
});
} catch (error) {
return [error.toString(), 'error'];
}
return await parse_context(context);
};
function parse_context(context) {
var body = [];
context.messages.forEach(message => {
body.push(message.text);
});
body = body.join(' \n');
return [body, ''];
}
module.exports = {
grab_context
};
我仍然在研究异步编程,所以我可能遗漏了一些明显的东西。我认为基本上 res.send
之类的东西可能需要在 grab_context
调用之前出现?但同样,不确定这里的最佳流量。
更新
我也在 API 路由中尝试过这种模式,但仍然超时:
slack.grab_context(req).then((body, images) => {
knex ...
})
你的超时可能不是你想的那样。据我所知,它来自 grab_context
。考虑以下 grab_context
async function grab_context_simple() {
try {
const context = { hello: 'world' }
} catch (error) {
return [error.toString(), 'error']
}
return context
}
grab_context_simple() /* => Promise {
<rejected> ReferenceError: context is not defined
...
} */
您正在尝试 return context
在定义它的 try 块之外,因此 grab_context
将以 ReferenceError
拒绝。很可能这个错误此刻正在被吞噬,所以它看起来像是超时了。
修复方法是在 grab_context
async function grab_context(req) {
try {
const context = await Slack.conversations.history({
channel: req.body.channel_id,
latest: req.headers['X-Slack-Request-Timestamp'],
inclusive: true,
limit: 5
});
return await parse_context(context); // <- moved this
} catch (error) {
return [error.toString(), 'error'];
}
};
I'm wondering the best way to set this up.
您可以添加更高级别的 try/catch
块来处理由 /foo
路由引起的错误。您还可以通过在 async/await 和承诺链之间保持一致来提高可读性。下面是如何将 async/await 与 knex
以及前面提到的 try/catch
块
const express = require('express');
const router = express.Router();
const knex = require('../../db/knex.js');
const slack = require('../../services/slack_helpers');
const insertInto = table => payload => knex(table).insert(payload)
const onFooRequest = async (req, res) => {
try {
let [body, images] = await slack.grab_context(req);
const text = await insertInto('texts')({
body: body,
image_ids: images,
});
res.send('worked!');
} catch (err) {
res.send(err);
}
}
router.post('/foo', onFooRequest);
module.exports = router;