Rails: writing a record asynchronously - ruby-on-rails

in my Rails 5 RC1 app write some log entries into a DB table through an ActiveRecord model.
Writing this log entry takes a couple of milliseconds and delays the response for the end user.
I am searching for a mechanism how I can execute the log-writing into the "background" so it is not blocking/delaying the response (kind of "fire-and-forget"). Do you have some hints on how to do that?
I tried to wrap the respective part into
Thread.new { code }
But this even seems to further delay the response a few MS.
I appreciate any hint!
Thanks and regards

Try looking into messaging services like RabbitMQ for asynchronous transactions and activities. I use RabbitMQ in exactly the way you describe.

If you are using ActiveJob, you could use :async, which looks to be the default queue_adapter for ActiveJob. However, this doesn't persist jobs between restarts and is not really recommended for production.
See Rails 5 changed Active Job default adapter from Inline to Async.

Related

How to migrate .delay tasks from Sidekiq to Active Job

Given an existing rails app with background processes managed by Sidekiq.
How can I migrate calls such as:
Model.delay.some_action()
From Sidekiq's syntax to Active Job's back-end agnostic syntax?
Update:
#craig.karminsky has pointed out the well-written Sidekiq to Active Job Wiki Page. This page addresses mailers.
Old Sidekiq syntax:
MyMailer.delay.send_message()
Active Job syntax:
MyMailer.send_message().deliver_later
That's a good solution for mailers, but how can I migrate non-mailer calls to .delay such as:
NotAMailer.delay.do_something()
Mike Perham, the creator of Sidekiq, has a very good Wiki page up for just such a situation.
I've made a gem for that on top of activejob: https://github.com/cristianbica/activejob-perform_later/. However the gem isn't very tested and this pattern is not a good one. Having code through your application that gets executed delay it will make your app hard to maintain and trigger all kind of bugs

rails - postgres trigger action with a method?

I'm creating a new rails APP that's works with the same postgres DB as my API.
The API and the APP has a couples of common models.
Exemple :
The API and the APP has a Connection model
The APP will create a simple connection in the DB and the API will do the rest (like handler using the connection for many things )
So I wanted to use Hair Trigger that allowed to trigger a DB insert, or update and like it to a DB behavior that's will be execute.
But I would like to execute a method from one of my helpers.
like that :
class Connection < ActiveRecord::Base
trigger.after(:insert) do
SomeObject.method()
end
end
I can't use after_create because the creation action is not done on the same server (but same DB)
any ideas ?
Thanks !
The reason why Hair Trigger only supports SQL is that it's purpose is to help you maintain database triggers (https://www.postgresql.org/docs/9.6/static/sql-createtrigger.html).
Database triggers are decoupled from your application and will only be able to trigger SQL inside your database. It won't actually be able to trigger any code inside of your application.
A solution to your problem would be to use events. If you ever worked with Javascript you might have come across Event and EventListener before. The purpose of events is to decouple your code. One part of your application sends an event when an action has been taken e.g. Something was inserted into the database. Other parts, as many as you like, of your application can then subscribe to these events and take the actions necessary.
Since you are working with Rails I would suggest you to take a closer look at the Wisper gem (github.com/krisleech/wisper). If your App and API; like you are describing, lives in different processes (or servers), you should look into using a background worker to handle the events asynchronously. A common approach to this is to use Sidekiq Wisper (github.com/krisleech/wisper-sidekiq) that enables you to trigger the events async using Sidekiq as your background worker.
For a good introduction to the subject, here's a guide to get you started (I'm not the author): http://www.g9labs.com/2016/06/23/rails-pub-slash-sub-with-wisper-and-sidekiq/
There might be easier ways to solve the issue you are facing but you will need to post some more details on the use case for us to give you some better pointers.

Mongoid.override_database in Sidekiq and simultaneous Rails requests

I'm just wandering when can I safely use Mongoid.override_database.
If I use it inside Sidekiq worker is DB going to be changed only for the worked which has called the override_database method?
How about using it in standard Rails controller? Is there any situation where it shouldn't be used (where it could cause problems)?
At first I've used .with(database: 'xyz') when I needed to change the DB, but then I've found out that it doesn't work on relational fields...

after_filter or Sidekiq for managing a page_view information

I have a Rails app and currently I create a PageView object for each API access. Our API is still pretty fast (50% of request are < 50ms) but most of the time is spent in writing the PageView to our MySQL instance.
I was thinking of using Sidekiq but the problem has been passing larger objects which are strongly discouraged in Sidekiq - https://github.com/mperham/sidekiq/wiki/Best-Practices#1-make-your-jobs-input-small-and-simple
What would be a better option? Our current solution of an after_filter is OK but would just like to get more performance.
Edit
I am trying to not have scenarios like this (granted an isolated incident of 1 request but using a cloud MySQL provider):
mysql is really quite fast. Your time is probably spent in AR validations or callbacks. Drop down to a raw DB connection and SQL to cut as much Ruby out:
ActiveRecord::Base.connection_pool.with_connection do |conn|
conn.insert "INSERT INTO ..."
end

Rails Activemailer with RabbitMQ (ruby on rails)

I am running a Ruby on Rails application, presently using delayed_job to send emails. But I want to switch to RabbitMQ messaging queue. I am not able to find any useful resource to get started with it. I read many RabbitMQ docs and what not. Please get me some heads up to accomplish this task.
RabbitMQ integrations for Rails heavily depend on eventmachine and callback-based code. This will make your code really complex, and you will need to make all your code aware of the event loop.
For instance, you can't use the same code if you deploy behind thin (which already has a running event loop) or behind unicorn (in which you have to instantiate a reactor and manage its lifecycle).
On the other side, you can abstract this to an actual job queue (Resque is already much faster than DJ, Sidekiq smokes its pants off, and Beanstalkd/Stalker is a very good contender) which is probably going to be compatible to the Rails.queue abstraction in rails 4.
In Rails 4, you have also the option to configure all ActionMailer to be async by default (thereby delegating to any configured job queue). http://reefpoints.dockyard.com/ruby/2012/06/26/rails-4-sneak-peek-async-actionmailer.html
If you are looking to kill 2 birds with one stone, and your sending an email needs are based on active record lifecycle events (which they almost always are), you should check out my gem.
https://github.com/jasonayre/active_pubsub
It was built on the bunny gem and works much like active record observers, except you run the subscribers in a separate process. (this is actually just a bonus functionality, its intended largely to allow multiple rails apps to subscribe to each others events) -- I.E.
#user model
class User < ::ActiveRecord::Base
include ::ActivePubsub::Publishable
publish_as "myapp"
end
#subscriber
class PostSubscriber < ::ActivePubsub::Subscriber
observes "cms"
as "aggregator"
on :created do |user_hash|
user = User.find(user_hash[:id])
#or whatever
WelcomeMailer.deliver(user)
end
end
== async delivery + keeps your controllers slimmer.
If you are looking for a great Ruby background jobs processing library to replace delayed_job you should give Sidekiq a try. There even is a recent Railscast about it here.
You can get an overview on Background Jobs Gems on Knight.io (I started this site).

Resources