Martin Šťáva Martin Šťáva - 12 days ago 4
reST (reStructuredText) Question

Firebase transactions via REST API

I find transactions (https://www.firebase.com/docs/transactions.html) to be a cool way of handling concurrency, however it seems they can only be done from clients.

The way we use Firebase is mainly by writing data from our servers and observing them on clients. Is there a way to achieve optimistic concurrency model when writing data via REST API?

Thanks!

Answer

You could utilize an update counter to make write ops work in a similar way to transactions. (I'm going to use some pseudo-code below; sorry for that but I didn't want to write out a full REST API for an example.)

For example, if I have an object like this:

{
   total: 100,
   update_counter: 0
}

And a write rule like this:

{
   ".write": "newData.hasChild('update_counter')",
   "update_counter": {
      ".validate": "newData.val() === data.val()+1"
   }
}

I could now prevent concurrent modifications by simply passing in the update_counter with each operation. For example:

var url = 'https://<INSTANCE>.firebaseio.com/path/to/data.json';
addToTotal(url, 25, function(data) {
   console.log('new total is '+data.total);
});

function addToTotal(url, amount, next) {
   getCurrentValue(url, function(in) {
      var data = { total: in.total+amount, update_counter: in.update_counter+1 };
      setCurrentValue(ref, data, next, addToTotal.bind(null, ref, amount, next));
   });
}

function getCurrentValue(url, next) {
   // var data = (results of GET request to the URL) 
   next( data );
}

function setCurrentValue(url, data, next, retryMethod) {
   // set the data with a PUT request to the URL
   // if the PUT fails with 403 (permission denied) then
   // we assume there was a concurrent edit and we need
   // to try our pseudo-transaction again
   // we have to make some assumptions that permission_denied does not
   // occur for any other reasons, so we might want some extra checking, fallbacks,
   // or a max number of retries here
   // var statusCode = (server's response code to PUT request)
   if( statusCode === 403 ) {
       retryMethod();
   }
   else {
       next(data);
   }
}
Comments