Acceptance tests with RSPEC, private_pub and Resque - ruby-on-rails

I'm looking for a bit of guidance on writing acceptance tests for a process that uses Ryan Bates' private_pub gem (https://github.com/ryanb/private_pub) and Resque.
In my controller I have an execute action that queues up a file generation process in Resque and then makes an AJAX request to display a "waiting" modal window. The modal window contains the javascript to subscribe to a private_pub channel and wait for a message on that channel. Upon completion of the file generation process in the Resque worker, a message with the newly generated file name is pushed to private_pub. The javascript in the modal receives the message and uses the filename to kick off a download of the file in the browser.
I'm looking for suggestions on techniques to run tests on this process. I've considered mocking the private_pub server (not sure how to even accomplish this after much Googling) so that it simply returns a pre-staged file. Basically I think I need a way to exercise my workflow without the need to run a private_pub server and the whole Resque infrastructure in my test environment.

I'd recommend stubbing out the call to the Resque worker and simply returning what you'd expect it to return. Then test the Resque worker code in a separate test.
If your goal is specifically to test the functionality of the modal window, you could write a test that simply makes the call to the Resque worker and use Capybara to determine if the modal shows up. In this example, you would not want to stub the Resque call - simply end the test after you've found the modal window appears.

Related

External web service for sending background emails in rails

I've used this instructions and sent "Welcome" mail to my signed up user. But this makes the user wait for 5-8 seconds because the server is trying to complete this mail thing.
I don't want the user to wait until the mail is sent but immediately see the "Mail has sent" message. So this brings me background jobs in Rails.
There are many options like delayed_job, Resque etc for background jobs in Rails. But to use these kind of solutions, as I understand:
1- Create a background job
2- Run this job
Let's say I used one of the background job solutions, so then I need something else to run also this job, like cron job...
I think just for sending sign-up and password reminder emails, another easier solution should be possible. I mean like another external service that 1- I'll create a template for each kind of mail I'll send, 2- I'll pass some arguments like receiver_email, template_id, receiver_username, password_link etc... With that way, I won't need any background job, and the user will not wait.
I came across some other gem called "sucher_punch" but as I understand from the people's messages and posted problems, with using heroku, this gem can fail for some reasons of heroku dynos and the mail may not be sent, and you don't know it.
Anyway, what is the general way that rails developers handle this email issue? Maybe I can also use sendgrid like the way I explained above, can I ?
Sending emails in the background is such a common use case, Rails 4.2 introduced a #deliver_later method in ActionMailer to provide seamless ActiveJob integration.
You don't need to set up a cron job to check if there are any jobs in the background queue. Sidekiq, Resque or DelayedJob will take care of that for you.
It seems Sendgrid does allow creating templates and sending variable content to fill them up, but that feature doesn't undermine the benefits of making that call asynchronously. In fact, deferring it to the background also has the added benefit of not disrupting user experience if the external resource(Sendgrid) is unavailable.
You should try installing one of the background processing solutions you mentioned(I recommend sidekiq) and take advantage of the ActionMailer + ActiveJob integration.

Rails 4: How to send mail in a separate thread?

I have an application that needs to occasionally send an email blast to the entire user base when an admin does something. This was working fine, but when there are a lot of users, the page for the admin will wait until all the mail is sent, which is undesirable.
To mitigate this, I tried sending email in a new thread:
t = Thread.new do
User.all.each do |user|
Mailer.email(user).deliver
end
end
at_exit{ t.join }
This worked fine, but then in my test suite, I can't test to ensure the email sending works:
# This test now fails with the new Thread above
test "admin action should send email blast" do
assert_difference("ActionMailer::Base.deliveries.count", User.count) do
post :action
end
end
So my questions are:
Is this method the best way to send email in a new Thread? Or is there a gem available that handles this kind of interaction?
How can I test that the emails are sent in my test suite if the sending is done in a new thread? Is there a way to check to wait for all threads to finish?
In rails 4.2 there's a special class that handles jobs called ActiveJob, active job allows you to queue long tasks for another process to handle them in the background, also you can queue tasks for a certain time, like for example "send this email tomorrow at 8 am".
For these queues to get handled you need to choose a backend to handle them, here's a list of backends that support ActiveJob
Each has it's pros and cons, sidekiq for example is a multithread handler, so it uses lower memory, while for example sucker punch uses the same thread as the main server, so it uses a lot less memory, suitable if you have a low memory server that can't handle a second ruby thread.
As for the testing part, rails guide already explains how to test your emails and test things like if emails has been queued or not, and test that the right template was rendered, and if it contains the right text.
I think you want to send mail asynchronously, For that you may use many gems like - delayed jobs, sidekiq etc. I would personally recommend to use sidekiq as its faster and used Redis in memory db behind the scene.
With Rails 4.2, Active jobs are introduced, so using it has advantage that you can switch from one queuing system to other without having any worry at any time and you can specify which queing machinery yiu want like
module YourApp
class Application < Rails::Application
# Be sure to have the adapter's gem in your Gemfile
# and follow the adapter's specific installation
# and deployment instructions.
config.active_job.queue_adapter = :sidekiq
end
end
I prefer using a queue based approach for async tasks. [Delayed job] (https://github.com/collectiveidea/delayed_job) is one option, but I prefer using [sidekiq] (http://sidekiq.org).
[Here] (http://blog.remarkablelabs.com/2013/01/using-sidekiq-to-send-emails-asynchronously) is an example of sending emails asynchronously using sidekiq.
Best way to send emails in separate threads is to use delayed jobs or similar gem.
https://github.com/collectiveidea/delayed_job
With delayed jobs gem, you can also send emails or do something else in different threads at scheduled time.
Another option is to use sidekiq, install sidekiq gem and add this line to application.rb file
config.active_job.queue_adapter = :sidekiq

pusher-fake specs not able get the triggers sent from a delayed_job

I have job running in background which triggers the pusher events frequently to the home page of the application to show the status of the process running.
When testing the process using rspec and pusher-fake, I see that the triggers are working for test which are directly coming from normal controller methods. But the triggers coming from background job are not observed by the pusher-fake specs.
I exactly followed the way pusher-fake example's specs are written https://github.com/tristandunn/pusher-fake-example.
Let me know how this problem can be resolved.
Thanks.

Wrap Rails controller into Delayed Job

The gem named Delayed Job (https://github.com/collectiveidea/delayed_job) can do many things in background. But can it run a Rails controller in background so that it still will respond to HTTP requests and return results?
No, this would require Delayed Job to spin up a server. This does not work because a server is already running with your App.
What exactly are you trying to archive? If you have your Rails app running, it will be able to respond to HTTP requests that might come.

Rails 3 Asynchronous External Programs

I am designing a web service under Rails 3.2.8 which will execute external program for the users, the expected use case is:
1) User fill a form of parameters and submit the request
2) Rails execute a Matlab program based on user request. It would last a few minutes (less than 3mins) and generate a result file shows that the program is finished
3) During this process, redirecting user to a page shows "loading" status, and monitoring if the result file has been generated
4) Once the result file is generated, reload the page via AJAX and display the results.
Is there a "rails" way to do so? I did this before in JAVA SSH framework but pretty painful. What will be the tools I need? For example, do I need gems like backgroundjob
to manage the task queue? Or are there any "one-stand" gems can handle this? Thanks!
Use one of several job queue providers. Examples include DelayedJob (simplest one ever, no additional pieces required), Resque and Sidekiq (much faster, but you need a small Redis server to use them).
A "job" will be (depending on the provider) a class or instance, which implements the execution. If it implies running something in the shell, you can do it like
%x[matlab command --options > output.ext]
(it's just an example, you can use string interpolation too: %x[#{executable_name}])
I kind figured out what to use during the whole process:
1) User fill a form of parameters and submit the request
Using the method from this rails cast: http://railscasts.com/episodes/219-active-model for server side validation and gem 'client-side-validations' to enable client side check.
2) Rails execute a Matlab program based on user request. It would last a few minutes (less than 3mins) and generate a result file shows that the program is finished
Using gem 'DelayedJob' for task management and 'ChildProcess' to start the Matlab program.
3) During this process, redirecting user to a page shows "loading" status, and monitoring if the result file has been generated
Monitoring child process as well as the existence of the result file to check whether the task is finished.
4) Once the result file is generated, reload the page via AJAX and display the results.
Using polling method from this rails cast: http://railscasts.com/episodes/229-polling-for-changes to update the result page. I am not using pushing although it would be more secure - as polling seems to be a more light-weighted solution and can meet my requirements.
Obviously this is not the best practice, but satisfies my needs and easy to implement. Thanks for all the comments and answers.

Resources