在让异步操作继续进行的同时响应客户端是否 运行 是个好主意?
Would giving response to client while letting asynchronous operation continue to run a good idea?
所以我需要实现一个“昂贵的”API 端点。基本上,user/client 需要能够创建现有用户的“组”。
所以这个“创建群组”API 需要检查每个用户是否满足条件,即同一群组中的所有用户都需要来自同一地区、同一性别、同一年龄段等。此操作可能会非常昂贵,特别是因为对一个组中的用户数量没有限制,因此客户端可能会请求 1000 个用户的组。
我的想法是端点只会在数据库中创建条目并将“组”标记为待定,同时检查过程仍在进行,然后在完成后,它将组状态更新为“已完成”或“error”和错误消息,如果状态仍然未决,则客户端需要定期获取状态。
我的实现思路是这样的
const createGroup = async (req, res) => {
const { ownerUserId, userIds } = req.body;
// This will create database entry of group with "pending" status and return the primary key
const groupId = await insertGroup(ownerUserId, 'pending');
// This is an expensive function which will do checking over the network, and would take 0.5s per user id for example
// I would like this to keep running after this API endpoint send the response to client
checkUser(userIds)
.then((isUserIdsValid) => {
if (isUserIdsValid) {
updateGroup(groupId, 'success');
} else {
updateGroup(groupId, 'error');
}
})
.catch((err) => {
console.error(err);
updateGroup(groupId, 'error');
});
// The client will receive a groupId to check periodically whether its ready via separate API
res.status(200).json({ groupId });
};
我的问题是,这样做是个好主意吗?我是否遗漏了一些我应该考虑的重要事项?
是的,这是 long-running 操作的标准方法。与其提供 createGroup
API 来创建和 returns 一个组,不如将其视为具有 addGroupCreationJob
API 来创建和 returns工作。
您可以使用通知 API(通过 websocket、SSE、webhook 等发送事件),甚至订阅处理进度,而不是轮询(定期获取状态以检查它是否仍处于待处理状态)。但是可以肯定的是,check-status API(通过作业标识符上的 GET 请求)是所有类型的客户端都可以使用的最低公分母。
Did I not consider something important?
故障处理变得越来越复杂。由于您不再在单个事务中创建组,您可能会发现您的应用程序处于某种中间状态,例如当服务在 checkUser()
调用期间崩溃(由于不相关的事情)时。您需要一些东西来确保您的数据库中没有未决的组,其实际创建过程是 运行。您需要为用户提供重试作业的能力 - 如果在 error
状态下已经有一个具有相同标识符的组,insertGroup
会工作吗?如果将组和作业分成独立的实体,是否需要确保没有两个挂起的作业试图创建同一个组?最后但同样重要的是,您可能希望允许用户取消当前 运行 作业。
所以我需要实现一个“昂贵的”API 端点。基本上,user/client 需要能够创建现有用户的“组”。
所以这个“创建群组”API 需要检查每个用户是否满足条件,即同一群组中的所有用户都需要来自同一地区、同一性别、同一年龄段等。此操作可能会非常昂贵,特别是因为对一个组中的用户数量没有限制,因此客户端可能会请求 1000 个用户的组。
我的想法是端点只会在数据库中创建条目并将“组”标记为待定,同时检查过程仍在进行,然后在完成后,它将组状态更新为“已完成”或“error”和错误消息,如果状态仍然未决,则客户端需要定期获取状态。
我的实现思路是这样的
const createGroup = async (req, res) => {
const { ownerUserId, userIds } = req.body;
// This will create database entry of group with "pending" status and return the primary key
const groupId = await insertGroup(ownerUserId, 'pending');
// This is an expensive function which will do checking over the network, and would take 0.5s per user id for example
// I would like this to keep running after this API endpoint send the response to client
checkUser(userIds)
.then((isUserIdsValid) => {
if (isUserIdsValid) {
updateGroup(groupId, 'success');
} else {
updateGroup(groupId, 'error');
}
})
.catch((err) => {
console.error(err);
updateGroup(groupId, 'error');
});
// The client will receive a groupId to check periodically whether its ready via separate API
res.status(200).json({ groupId });
};
我的问题是,这样做是个好主意吗?我是否遗漏了一些我应该考虑的重要事项?
是的,这是 long-running 操作的标准方法。与其提供 createGroup
API 来创建和 returns 一个组,不如将其视为具有 addGroupCreationJob
API 来创建和 returns工作。
您可以使用通知 API(通过 websocket、SSE、webhook 等发送事件),甚至订阅处理进度,而不是轮询(定期获取状态以检查它是否仍处于待处理状态)。但是可以肯定的是,check-status API(通过作业标识符上的 GET 请求)是所有类型的客户端都可以使用的最低公分母。
Did I not consider something important?
故障处理变得越来越复杂。由于您不再在单个事务中创建组,您可能会发现您的应用程序处于某种中间状态,例如当服务在 checkUser()
调用期间崩溃(由于不相关的事情)时。您需要一些东西来确保您的数据库中没有未决的组,其实际创建过程是 运行。您需要为用户提供重试作业的能力 - 如果在 error
状态下已经有一个具有相同标识符的组,insertGroup
会工作吗?如果将组和作业分成独立的实体,是否需要确保没有两个挂起的作业试图创建同一个组?最后但同样重要的是,您可能希望允许用户取消当前 运行 作业。