-
24
Feb
Sooner or later in the life cycle of any application, there comes a time when it makes sense to explore areas where backgrounding processes might improve your Users’ experience. Right now, if you’re looking to do that, the place to turn is Workling.
The obvious candidates for this kind of backgrounding include sending emails and search engine indexing. In our app, though, the first performance killers to present themselves were several calls to third party APIs. Due to the limitations of one of these APIs, and some funky accounting requirements, one process can take as many as 24 separate calls (some lookups, some method calls). Now, the API response times are pretty good, but no matter how quick they may be, it’s obvious that this is going to add some inconvenient overhead to what should be a fast, responsive User session.
In working to background this particular process, I came up against some Workling limitations that may not be typical, or well documented. (Actually, they may be well documented, but since Google just kind of assumes that when you type “workling” you really mean “working”, it’s not always easy to find the pertinent posts.) Anyway, without further ado, some questions/problems I came across, and the answers that worked for me:
1. The standard how-to, startup guide has you calling the worker from the controller, but is it possible to call it from within a model instance?
This one was pretty easy to test, and the answer seems to be yes, you can. I understand it may not be the best practice, but should you find it preferable, calling the worker from within a model does not appear to present a problem. (For my purposes, it ended up making sense to call it from the controller, but I did have it working from a model at first.)
2. Can you pass a model as one of the options’ hash values?
No. Trying this approach, you will very quickly run up against errors like “A copy of ModelName has been removed from the module tree but is still active!”
3. Do ActiveRecord associations work in the worker process?
That would be a no. It’s not a question I thought to ask initially, but I came up against it pretty early in the process. I could be wrong here, but in my experience, it seems like if you want to deal with a given object, you have to load it from within the worker. For me, any model methods that directly interacted with the DB failed (including simple lookups). Which made for some creative, maybe-a-little-hacky coding on my part.
Update: It looks like the reason that ActiveRecord associations were breaking down for me wasn’t a limitation of Workling, but rather an issue with a default setting in the workling plugin. In workling/lib/workling/remote/runners/spawn_runner.rb you’ll find the following line of code:
@@options = { :method => (RAILS_ENV == "test" || RAILS_ENV == "development" ? :thread : :fork) }
Which is probably all well and good, so long as you’re on Rails 2.2, in which Rails is made thread safe. If, however, you’re running Rails 2.1 still, you’re going to want to change that line so it always uses :fork. Changing that solved the association related issues I had been having.
4. What about calling it from within a transaction?
This is potentially problematic, but not necessarily. For instance, if the worker needs to access a record that was created inside the same transaction. When it goes looking for it in the database, it may be out of luck. In retrospect, it made sense, but it didn’t occur to me until I hit the wall.
I think that covers all of the little gotchas I’ve come across so far. We’ve yet to deploy this latest code, or even to add Starling into the mix, so there’s always the possibility of more. If so, I’ll be sure to update this.
- Published by James in: Programming
- If you like this blog please take a second from your precious time and subscribe to my rss feed!
2 Responses to “Working with Workling”
Leave a Reply