Replication delays in a Master-Slave DB configuration

The problem I’m trying to solve is best described by TaskRabbit in the post titled Makara: a read-write splitting adapter for Active Record.

After using Octopus for a while we noticed that, in some rare cases, our web app could be faster than our database replication. For example, if you just posted a Task, the next page we rendered for you is the public Task page so you can confirm that everything looks as you expected. At this point, the INSERT statement that just ran on the master database may not finsihed replicating to the SLAVE(S).If you then query the slave there’s a chance you’ll get a RecordNotFound error.

They solved this problem with the concept of a “sticky” DB session:

It was this type of error that prompted us to develop the ‘sticky’ notion of choosing a database. In a nutshell, once you have modified a record (INSERT, DELETE, or UPDATE), you should continue to use whichever database you performed that action on for the remainder of your request. This ensures that the data you are using is consistent throughout the request. This notion of sticking was also very important in our Delayed Job workers, which often performed more requests faster than our web servers. Keeping a consistent database is also important when traversing any belongs_to relationships for obvious reasons.

TaskRabbit packaged the solution as a RubyGem, Makara.

Master/Save configurations have been discussed before, but not in the context of solving replication delays:

Would taking the approach of a “sticky” DB session be the best solution to the problem? Are there other approaches in terms of application design that would avoid this problem altogether?

If the “sticky” DB session approach is appropriate, I thought I would implement it with a process acting as a proxy for the Ecto repo:

  • start a proxy (process) for a request
  • proxy repo functions (e.g. one, all, insert)
  • read functions such as all would be directed to the read store
  • write functions such as insert would be directed to the write store
  • once a write function was called, all following function calls would use the write store for the rest of the request.

Is there a better approach?

Thank you for help!