Rails, callbacks, workers, and the race you never expected to lose
logicalfriday.com
Rails, callbacks, workers, and the race you never expected to lose
1–10 of 28 posts
Re: Rails, callbacks, workers, and the race you never expected to lose
#2And I liked author's solution of tracking attribute changes. But may be there is a cleaner way. I had similar problem where, I needed a handle on after_commit :on => :update but in observer.
Re: Rails, callbacks, workers, and the race you never expected to lose
#3Re: Rails, callbacks, workers, and the race you never expected to lose
#4These days if I find myself wishing I have a callback that probably means a related model method or controller needs to be one line longer than it is right now. (e.g. I moved the welcome email out of the after_save and into the controller in charge of online signups months ago. This was the right call, as it means that e.g. my magic administrator create-a-free-account-for-a-customer-who-pays-via-PO button doesn't actually mail them prior to their account being configured correctly.)
Re: Rails, callbacks, workers, and the race you never expected to lose
#5For this and related predictability/absence-of-surprise reasons, I have generally moved away from ActiveRecord callbacks in my Rails projects. It's very easy to forget that you e.g. have an after_save defined for accounts which made sense when accounts necessarily represented people with credit cards in the system but doesn't make sense for e.g. people paying via purchase order. It is also easy to forget an after_sav…
Nothing against the OP, it does explain a common edge case that many people will run into and for that it's a good article, but I wish more people would see the violations of SRP going on here and try to lead people away from this trap.
I'd recommend watching http://www.youtube.com/watch?v=CGN4RFkhH2M (Hexagonal Rails GoRuCo talk) for one way to re-architect to get away from these inter dependencies.
Re: Rails, callbacks, workers, and the race you never expected to lose
#6To tell a quick little story, I have experienced this issue in a system on a very unpredictable way. It cost me hours (days?) of repeated bug hunting to figure out what was happening.
So, our users will save an "Entity". The entity is actually pretty complex, and has the potential to span 40-50 tables. (O how I wish I used a Document Store rather than relational). Anyway, when the "entity" gets saved, I need to update Solr search, with an updated reflection of the model. There are two flags within this model, "enabled" and "deleted", and I use these flags to filter on the Documents within Solr.
All jobs are sent to Solr by going through a Gearman Job Server worker process.. However, the worker, was receiving the job before the database had persisted the updated model, so it was always one snapshot before the user initialized the request.
But oddly enough, this issue would only ever happen when the server was under very very small load. I could not for the life of me track this issue down, and it took me months before I realised this was almost akin to a race condition, especially since when under load the bug never happened... And.. If I artificially added load, the bug wouldn't happen. It would only happen when the server was running smoothly.
Once I spotted this, I was able to fork the request off to Gearman at the correct time, (rather than as a prePersist lifecycle event that I was previously).
I definitely learnt a lot from this little issue. It was such a simple issue, that eluded me for months, and just goes to show, that not all code runs the same... given different conditions, (ie Load), you will find that your code can behave differently.
Re: Rails, callbacks, workers, and the race you never expected to lose
#7Re: Rails, callbacks, workers, and the race you never expected to lose
#8For this and related predictability/absence-of-surprise reasons, I have generally moved away from ActiveRecord callbacks in my Rails projects. It's very easy to forget that you e.g. have an after_save defined for accounts which made sense when accounts necessarily represented people with credit cards in the system but doesn't make sense for e.g. people paying via purchase order. It is also easy to forget an after_sav…
One thing to keep in mind when moving logic out of callbacks is that you'll no longer get the implicit transaction that ActiveRecord wraps around the whole callback cycle, so you have to be a bit more hands-on with managing transactions.
Re: Rails, callbacks, workers, and the race you never expected to lose
#9Re: Rails, callbacks, workers, and the race you never expected to lose
#10For this and related predictability/absence-of-surprise reasons, I have generally moved away from ActiveRecord callbacks in my Rails projects. It's very easy to forget that you e.g. have an after_save defined for accounts which made sense when accounts necessarily represented people with credit cards in the system but doesn't make sense for e.g. people paying via purchase order. It is also easy to forget an after_sav…
As a sort of half-way house between using lifecycle callbacks and sticking everything in the controller, I've just moved the main app I work on to a pub-sub event system, which is working out quite nicely. Controllers or mutator methods no longer handle post-action tasks, they just announce what they did, and any interested listeners can act upon the event announced. This way we can have a listener that handles (for example) all post-action emailing, and we can test the logic for that in isolation. Controller logic is cleaned up too, so testing them becomes easier. On the flip side we have to write more comprehensive integration tests to make sure our listeners are all hooked up correctly, but it seems like a pretty good trade-off so far.
Enjoyed the OP nonetheless, though - I didn't know about ActiveModel#previous_changes, that's pretty nifty to have.