using rabbitmq with rails, how to create the endless loop process? - ruby-on-rails

In a rails web app, if I write messages to a queue like rabbitmq, how will clients be notified when a producer sends a message to the queue?
I'm guessing I have to create a seperate process that runs in the background to respond to messages correct? i.e. this code is outside of the scope of a web application.
If this is the case, is it possible to re-use the models/libs that are in the rails application already? do I have to copy this code in 2 places then?

It looks like your application requires what's usually called a background or worker process. This is a fairly common requirement for any moderately complex web application.
I'm guessing I have to create a seperate process that runs in the background to respond to messages correct?
Yes - you're right about this. Whilst it's perfectly possible to use threads to handle the background tasks (in your case, reading and processing messages from RabbitMQ), the standard and recommended route for a Rails application is to run a separate background process.
If this is the case, is it possible to re-use the models/libs that are in the rails application already?
Absolutely. The simplest possible way to get this working is by using Rails' built in runner command.
Another option is to create a ruby script which loads up your Rails application. For example, you could create the file my_script.rb in the root of your project, which might look something like this:
# Load my application:
require File.join(File.dirname(__FILE__), 'config/environment.rb')
# Now you can access your Rails environment as normal:
MyModel.all.each { |x| x.do_something }
If your needs become more complex, or you find that you need to run more than one background process to keep up with the volume of data you need to process, you might want to look at one of the many available libraries and frameworks which can help with this.
Once you've created your background process, you'll need a way to run it continuously when you deploy it to your production server. Whilst it's possible to use libraries like daemons, as suggested by ctcherry, I would recommend using a dedicated tool like upstart (if deploying to ubuntu) or runit. A good summary of the most popular options is available here.

You are correct, you do need a background process. And you can keep the code for that process in the lib folder of the Rails project if you like, I have done that before without issue, and it keeps related code together which is nice.
I used this library to create my long running process, it was quite simple:
http://daemons.rubyforge.org/
In order to re-use models from your rails application you can run a require on the config/environment.rb file to get everything loaded. (Set RAILS_ENV as an environment variable first to select the correct envrionement) From that point the script behaves as though you are inside a rails console session.

Related

Add web scraping data into the database at regular intervals [ruby & ror]

I'm learning full stack development through the free course at appacademy. If you are familiar with it. am almost finished with the rails section and have done also done the SQL & Ruby sections. I have yet to start JavaScript or React.
To test my abilities, I want to create an app. It will mostly be backend + HTML since I haven't covered front end yet.
The app function: ability for someone to provide a list of URLs for reddit posts and then track number of upvotes. I want to do this by scraping the reddit content using this. This is just to test my ability and not a real use case.
I only want to scrape once a day to keep the scraping function minimal. I also want to add a refresh button next to each post, so the user can refresh when they want to.
Questions:
Ill be creating a database that stores the value of upvotes. However, from what I have learned with the program, I do not know how I can use my ruby app to keep running my daily scraper function. If I create a file scraper.rb with the function that is on a time loop, how do I put this file in my ror created app? do i put it in the models, views or controllers folder? Will it run automatically if I run my ruby server? or is this part entirely separate? do I run two ruby apps at once? One for backends and one the actual page
For the refresh button, I think I would need to include a call to the scraper function in my controller before rendering the refreshed text. Does that sound right?
From your description, I would say that the scraper should be a model method and it needs to be wrapped around a rake task.
There are many ways you can achieve the periodic execution. Some of them are:
Whenever gem
Plain old cron job for running the rake task
If you deploy it in a PaaS like heroku, render.com or something similar, there are addons which can be configured to do the cron,like heroku scheduler or render.com cron.

Calling Models from Config Files

I am writing a ruby scheduler - namely rufus-scheduler and there are commands i need to write in the initializers section inside the config folder to perform a task every 1 minute or so. I am trying to access a method from a module within this. So my code would look like
scheduler.every("1m") do
puts("HELLO #{Time.now}")
ModelName.methodname("WHAT ARE YOU DOING")
end
This somehow doesn't perform the necessary operation in the model. Also im not sure if this is the right way to do things - such as call a model inside a config file. Is there a better place to put this code in the Model? Or is calling a Model within config files perfectly good practice. I looked over the internet to see the usage of different types of files in ruby but couldn't find a proper material. Any help or guidance appreciated.
If you want to access models from stand-alone tasks the best way is to use the rails runner wrapper. For example, you'd call your script as:
rails runner call_model.rb
This loads in the Rails environment and then executes your script, eliminating the need to do that yourself. Models on their own will not work since they are lacking the context of Rails.
If that's not sufficient, you may need to load the Rails environment more directly by including config/environment.rb into your rufus-scheduler configuration.
It sounds like you actually want a real scheduled action of some sort. config files are for configuration, not for actual working code of that sort.
There are tons of ways to run scheduled tasks in rails.
google "rails daemons" or "rails scheduled tasks" to start you off.
Here's a good list of scheduled-task best practices using cron:
A cron job for rails: best practices?

Allowing a user to manually run a scheduled program from rails

As part of my web application I have a program that runs periodically during low activity times. However I want to allow the functionality to the user to be able to start the program manually. How can I do this? Where should I put my ruby program within the rails framework and how do I offer a link to commence the program then redirect to another page while the test is running. Thanks.
The code could be put in any controller but if you want the program to run quietly behind the scene without blocking your browser (pretty logic spec), you should trigger it using some tool like DelayedJob or Resque.
Great Railscasts here.

Is Rails appropriate for use with a non-web-centric app?

It seems to me that Rails shines when building web-centric applications such as the Depot online-store app presented in the Agile book or the Basecamp project management system. The crux of these applications is their web interface, and Rails gives you the tools to create these webapps quickly, easily, and elegantly.
But what if you have an application with a command line interface for which you'd like to add a front-end? For example, imagine an application which processes third-party EDI files - it gets them from an FTP server, parses them, inserts the data into a database and sends out reports via emails. The schedule of when the app should run, which reports should be generated, who should get the email, etc. is all configured in a database. And although the main point of the application is the processing of EDI files and you want to run it via cron, you'd like to build a web page to allow users to manage which reports they're receiving, how often they receive them, etc.
Both the command line app and the web page need to access the same data in the database. They should be able to share models and business logic. If the command line app already contains a library with a data access layer, is there a way to leverage this library within Rails? Or, conversely, is there a way to reuse Rails' models and controllers in an outside app? Or does it not make sense to use Rails as the web framework in this scenario?
You could always just include the ActiveRecord library (and ActiveSupport) in a regular ruby application, if you are just looking to abstract away the model layer for a db centric app.
Actually, most rails apps have a web interface and also a command-line interface - through rake.
The classical example are batch jobs that have to be run periodically, though cron or whenever. But it is also possible to run those tasks manually.
If I were you, I'd try building some rake tasks inside lib/tasks in order to map those command-line commands.

Rails best practice question: Where should one put shared code and how will it be loaded?

The rails books and web pages I've been following have all stuck to very simple projects for the sake of providing complete examples. I'm moving away from the small project app and into a realm of non-browser clients and need to decide where to put code that is shared by all involved parties.
The non-browser client is a script that runs on any machine which can connect to the database. Browser clients write commands into the database, which the script examines and decides what to do. Upon completion, the script then writes its result back. The script is not started by the RoR server, but has access to its directory structure.
Where would be the best place for shared code to live, and how would the RoR loader handle it? The code in question doesn't really belong in a model, otherwise I'd drop it in there and be done with it.
I'd put the shared code in the Rails project's /lib directory and consider making it a custom Rake task.
It really depends on how much you use this shared code. If you use it everywhere, then throw it in the lib folder (as has already been stated here). If you are only using it in a few places, you might want to consider making a plugin out of it and loading it only in the places that use it. It's nice to only load what you need (one of the reasons I'm loving merb).

Resources