I want to fan out data to 4 different nodes. Since firebase transaction process can be failed, what is the right approach to ensure that all 4 data will be saved?
Suppose that I have 4 functions for saving data, each will call a transaction.
Edit:
function saveToFirstNode(data, response) {
/*
* @param
* [response] is a callback function
* that indicates whether the save was successful
*/
firebase.database().ref('cars/' + data.carId)
.transaction(function(currentData) {
currentData.distance += data.distance;
return currentData;
}, function(error, commited, snapshot) {
if (error) {
response(false);
} else if (commited) {
response(true)
}
}, false);
}
function saveToSecondNode(data, response) {...}
function saveToThirdNode(data, response) {...}
function saveToFourthNode(data, response) {...}
1. Using the first approach
This approach uses nested callback function and calls progress() for every success in saving.
The downside is, if one of the saving process fails, it will re-save all data from the first to fourth.
var queue = new Queue(ref, options, function(data, progress, resolve, reject) {
saveToFirstNode(data, function(success) {
if (success) {
progress(25);
saveToSecondNode(data, function(success) {
if (success) {
progress(50);
saveToThirdNode(data, function(success) {
if (success) {
progress(75);
saveToFourthNode(data, function(success) {
if(success) {
resolve(data);
} else {
reject();
}
});
} else {
reject();
}
});
} else {
reject();
}
});
} else {
reject();
}
});
});
2. Using the second approach
This approach guarantee all data will be saved. When the saving process fails, it will retry from the failed specs, not from the first to fourth. But do you think it is an overkill just for doing 4 save? Is this the right approach?
Define specs in queue/specs:
{
"save_to_first_node": {
"in_progress_state": "save_to_first_node_in_progress",
"finished_state": "save_to_first_node_finished"
},
"save_to_second_node": {
"start_state": "save_to_first_node_finished",
"in_progress_state": "save_to_second_node_in_progress",
"finished_state": "save_to_second_node_finished"
},
"save_to_third_node": {
"start_state": "save_to_second_node_finished",
"in_progress_state": "save_to_third_node_in_progress",
"finished_state": "save_to_third_node_finished"
},
"save_to_fourth_node": {
"start_state": "save_to_third_node_finished",
"in_progress_state": "save_to_fourth_node_in_progress"
}
}
Queue code:
var saveToFirstNodeOptions = {'specId': 'save_to_first_node'};
var saveToFirstNodeQueue = new Queue(ref, saveToFirstNodeOptions, function(data, progress, resolve, reject) {
saveToFirstNode(data, function(success) {
if (success) resolve(data);
else reject();
});
});
var saveToSecondNodeOptions = {'specId': 'save_to_second_node'};
var saveToSecondNodeQueue = new Queue(ref, saveToSecondNodeOptions, function(data, progress, resolve, reject) {
saveToSecondNode(data, function(success) {
if (success) resolve(data);
else reject();
});
});
var saveToThirdNodeOptions = {'specId': 'save_to_third_node'};
var saveToThirdNodeQueue = new Queue(ref, saveToThirdNodeOptions, function(data, progress, resolve, reject) {
saveToThirdNode(data, function(success) {
if (success) resolve(data);
else reject();
});
});
var saveToFourthNodeOptions = {'specId': 'save_to_fourth_node'};
var saveToFourthNodeQueue = new Queue(ref, saveToFourthNodeOptions, function(data, progress, resolve, reject) {
saveToFourthNode(data, function(success) {
if (success) resolve(data);
else reject();
});
});
Which is the right approach? This question is not preference, as those two are completely difference approach and make huge impact on both performance and effectiveness.