【发布时间】:2021-11-29 14:31:03
【问题描述】:
我已经设法让 Cloud Task 正常工作。我对下面的代码没有任何问题,当在特定时间调用任务时,所有内容都会被删除。我无法解决的问题是如果任何 Promise 失败该怎么办,以及如何重试它们,因为任务已成功调用,但任务中的部分或全部 Promise 可能会失败。
我有 5 个承诺
1- 运行扇出/原子更新以从两个不同的数据库引用中删除一些值
2- 运行事务以减少用户路径上的属性
3- 运行事务以减少总帖子路径中的属性
4- 从存储中删除视频
5- 从存储中删除缩略图
据我了解,两个事务都将自行重试 (29x),但其他三个 Promise 我不知道如何处理。我一直在阅读不同的帖子并查看 Youtube 视频,但我无法理解这一点。除非我误解了Promise.all,否则这似乎不是一个可行的选择,因为it's all or nothing,当一个失败时,不会执行任何其他操作
const cors = require('cors')({origin: true});
const admin = require('firebase-admin');
admin.initializeApp({ ... });
exports.fireCloudTaskAtSpecificTime = functions.https.onRequest((request, response) => {
return cors(request, response, () => {
let userId = request.body.userId;
let postId = request.body.postId;
let videoId = request.body.videoId;
let thumbnailId = request.body.thumbnailId;
var updates = {};
updates[`/posts/${postId}`] = null;
updates[`/user-postIds/${userId}/${postId}`] = null;
const runTransactionOnUserPostCt = admin.database().ref('users').child(userId).child('postCt');
const runTransactionOnTotalPostCt = admin.database().ref('total-posts-count').child('postCt');
const videoIdPath = 'videos/' + userId + '/' + videoId;
const thumbnailIdPath = 'thumbnails/' + userId + '/' + thumbnailId;
admin.database().ref('posts').child(postId).once('value', snap => {
if (snap.exists()) {
// 1. fan-out
const root = admin.database().ref();
return root.update(updates)
.then(() => {
// 2. first Transaction
return runTransactionOnUserPostCt.set(admin.database.ServerValue.increment(-1));
})
.then(() => {
// 3. second Transaction
return runTransactionOnTotalPostCt.set(admin.database.ServerValue.increment(-1));
})
.then(() => {
// 4. delete video from Storage
const videoBucket = admin.storage().bucket();
return videoBucket.file(videoIdPath).delete()
})
.then(() => {
// 5. delete thumbnail from Storage
const thumbnailBucket = admin.storage().bucket();
return thumbnailBucket.file(thumbnailIdPath).delete()
})
.then(() => {
response.status(200).send('Ok - Everything Deleted');
})
.catch((error) => {
console.log('ERROR - Something Failed: ', error); // not sure what to do here or how to determine which one(s) failed
});
} else {
response.status(200).send('Ok - Post No Longer Exists'); // user already deleted it
}
.catch((error) => {
response.status(300).send('Task failed', error); // Only the HTTP code 2XX (from 200 to 299) are considered as a task completion and stops the retries. All other return code are considered as a failure and imply a retry.
});
});
});
【问题讨论】:
-
这对于 Google Workflows 来说可能是一个好故事...cloud.google.com/workflows 他们提供了步骤的顺序执行,如果某个步骤出现问题,似乎可以让您更正并继续。另一个想法可能是 Cloud Composer,它再次允许将工作分解为要执行的活动的 DAG。另一个想法可能是您希望所有步骤最终都执行而不考虑顺序......所以触发 5 个任务而不是一个。最后,考虑在 DataStore 中手动记录状态并自己处理成功和失败的情况。
-
@Kolban 感谢您的回复。我将看看前两个选项。触发 5 个任务而不是一个任务是一个有趣的选项 - 您是否有任何 SO 链接显示一个云任务同时触发多个处理程序?还是您的意思是 5 个单独的任务,每个任务都有自己的处理程序。这是一个有趣的想法,但似乎很昂贵。您是什么意思“在 DataStore 中手动记录状态”?你有任何关于那个的链接吗,这对我来说是新的
-
你好 Lance ...我确实是指 5 个独立的任务并行启动。如果结果是所有任务都必须完成并且它们是独立的,那么必须启动 5 个任务并且必须完成 5 个任务,如果其中任何一个任务失败,您就会知道并且可以重试它们。关于使用数据存储的最后一个概念......我想象你有一个应用程序,其中包含 5 个函数的代码,这些函数一个接一个地运行。当一个成功时,你更新一个数据库记录,说它成功了。如果一个失败了,整个 GCP 任务就失败了,当它重新启动时,它知道它已经做了什么。
-
您好,感谢您的帮助。我一直在思考你所说的关于 5 个独立任务的内容,这很有意义。虽然有 1 个问题,但我环顾四周,我认为不可能一次启动 5 个单独的任务。我将对您的数据存储想法进行更多研究。感谢您的帮助!
标签: firebase-realtime-database promise google-cloud-functions