I've managed to get a Cloud Task working. I've had no issues with the below code and when the task is called at a specific time, everything gets deleted. The issue that I can't wrap my around is what to do if any of the Promises fail and how to retry them because the task was successfully called but some or all of the Promises inside the task might fail.
I have 5 Promises
1- run a fan-out/atomic update to delete some values from two different database refs
2- run a Transaction to decrement a property at the users path
3- run a Transaction to decrement a property at the total-posts path
4- delete the video from Storage
5- delete the thumbnail from Storage
From my understanding both Transactions will retry on there own (29x) but the other three Promises I don't know how to handle. I've been reading different posts and looking at Youtube videos but I can't get the hang of this. Unless I'm misunderstanding Promise.all
, it doesn't seem like a viable option because it's all or nothing, when one fails nothing else gets executed
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.
});
});
});