0

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.

Edward Anthony
  • 3,354
  • 3
  • 25
  • 40
  • 1
    See http://stackoverflow.com/questions/30693785/how-to-write-denormalized-data-in-firebase – Frank van Puffelen May 30 '16 at 21:03
  • @FrankvanPuffelen I need to do transactional update to increment number. Multi-path update will not work for transaction update. Do you have suggestion? – Edward Anthony May 31 '16 at 21:32
  • You're not using a transaction in your current approaches either. And multi-location updates already succeed or fail atomically: either all locations are updated or none of them are.. – Frank van Puffelen Jun 01 '16 at 01:47
  • @FrankvanPuffelen In my current project, I need to increment the distance for each car. I've edited the first code in the question. Is there a way to use atomic transaction, or there's no other way than using the 2nd approach? – Edward Anthony Jun 02 '16 at 12:56

0 Answers0