Sinatra - Register startup and shutdown operations - ruby

I'm designing a web service using Sinatra and I need to perform certain operations when the service is started and some other operations when the server is stopped.
How can I register those operations to be fully integrated with sinatra?
Thanks.

The answer depends on how you need to perform your operations. Does they need to be ran for each ruby process or do they need to be ran just once for the service. I suppose it's once for all the service and in the case of the latest :
You might be tempted to run some code before your Sinatra app is starting but this is not really the behavior you might expect. I'll explain why just after. The workaround would be adding code before your sinatra class like
require "sinatra"
puts "Starting"
get "/" do
...
end
You could add some code to your config.ru too btw, would have the same effect but I don't which one is uglier.
Why is this wrong ? Because when you host your web service, many web server instances will be fired and each one will execute the puts method or your "starting" code. This is correct when you want to initialize things that are local to your app instance, like a database connection but not to initialize things which are shared by all of them.
And about the code firing at its end, well you can't (or maybe you could with some really ugly workaround, but you'll end with the same issue you get with the start).
So the best way to handle on and off operations would be to wrap it within your tasks firing your service.
Run some rake task or ruby script that do your initalization stuff
Start your web server
And to stop it
Run a rake task or ruby script that stops the server
Run your rake task or ruby script that does the cleaning operations.
You can wrap those into a single rake task, by starting your app server directly from ruby, like I did there https://github.com/TactilizeTeam/photograph/blob/master/bin/photograph.
This way you can easily add some code to get ran before starting the service, still keeping it into a single task. With some plumbing, I guess you can fire multiple thin instances and then allow you to start your cluster of thin (or whatever you use) instances and have still one task to rely on.
I'd say that adding a handler to the SIGINT signal could allow you to run some code before exiting. See http://www.ruby-doc.org/core-1.9.3/Signal.html for how to do that. You might want to check if Thin isn't already registering a trap for that signal, I'm not sure if this is handled in the library or in the script used to launch thin ( the "thin" executable that gets in your $PATH).
Another way to handle the exit, would be to have a watchdog process, that check if your cluster is running and could ensure the stop code is being ran if no more instances are running.

Related

Should I use rails5 ActiveJob default async adapter for small background job in production?

Rails app which handle and activation of a license using an external service, the external service sometime delays the handling of rails request to over 30s, which will then return an error to front end (I'm running heroku, so max is 30s).
I tried using ActiveJobs and the default rails async adapter (Rails 5), and I can see that is working in Heroku out of the box. I keep reading that I should be using another web process and for example redis, but if the background job should just be performed straight after the request is done and if is just hitting another API outside which may be slower, is it so bad to use the default async?
I can see that this is handle in an in-process thread but I don't see a reason for such small job to be having another web process.
I use the async adapter in production for sending emails. This is a very small job. An email could take up to 3 seconds to send.
The doc said it's a poor fit for production because it will drop pending jobs on restart. If I remember correctly, Heroku restarts dynos once a day.
If your job is pending during the restart, the job will be lost. For my case, a pending email during the restart is pretty slim. So far so good.
But if you have jobs taking 30 seconds, I'll use Resque or DelayedJob.
If for small background job in production, which does not require 100% persistence in case of failure/server restart, whose duration is relatively short and thus separate process would be an overkill, I'd recommend using Sucker Punch.
Sucker Punch gem is designed to handle exactly such case. It prepares execution thread pool for each Job you create, using the concurrent-ruby gem, which is (probably) the most robust concurrency library in Ruby. It also hooks on_exit to finish all the pending tasks, so I guess you can expect this gem to be more reliable than the AsyncJob.
One thing to note is that although Sucker Punch is supported on Active Job, the adapter is not well written. Or, at least, when you use Sucker Punch adapter, it's behavior would be just like that of async adapter. So, I'd recommend using bare Sucker Punch if you wanted something just a little more useful/robust than AsyncJob.

How to stop Event Machine in setup like this?

I have a Sinatra app, overall configured like described here sinatra docs.
It basically starts an event machine loop.
Now, If I want to write a RSpec test, how do I start server like this and shutdown it after?
I can do this from console by ruby server.rb, I may execute this command from spec file in test suit setup (however, I'm not sure if it is right). But then, even if I do so, how I stop it after? (and do I need or it will be stopped after test is finished?)
I think, in any case, you can use Rack::Test to test your Sinatra app. In order to run the specs, you don't need to run the server from the terminal.
Take a look at the documentation, you can find different examples:
http://www.sinatrarb.com/testing.html

need to check if eventmachine stop is scheduled

In my code that runs on eventmachine, how do I know if EventMachine::stop has been called?
I need this so that in my deferrable I do not log error messages that result solely from closing a connection and thus are not interesting from the operations stand point.
Is the only way to monkey patch the code?
If you have a peek at the source code for the pure-Ruby implementation of the EventMachine class in lib/em/pure_ruby.rb there's an instance variable defined called #stop_scheduled. It seems to be used internally to do exactly what you want to do - not perform some operations if we're currently shutting down.
Unfortunately this variable isn't exposed as part of the EventMachine API so you can't use it.
You might be stuck having to re-implement this kind of functionality yourself. Add a instance variable to the appropriate class(es)and have some guards around code that you don't want executed if a shutdown is in progress.

How to run an EventMachine application on your own production server?

I have just written my first EventMachine application. In development, to start the server, all I do is:
ruby myapp.rb
Which runs my application until I kill it with control+C. In production, this doesn't seem like the right way to do it.
How would I go about running this on my production server?
Check out daemons: http://daemons.rubyforge.org/ - a simple gem written for precisely this use case.
At PostRank we always used God to start/restart our production EventMachine APIs.
I prefer to have a completely external process handling my daemons rather than using something like the daemons library but that's a personnal preference.
You have many solutions out there, here those I know of, all of them will restart your application when it crash more or les quickly and some offer a management interface whether it is a cli or a web interface:
supervisord (http://supervisord.org/): he one I prefer so far
daemontools (http://cr.yp.to/daemontools.html): works well but can be anoying to configure
god as mentionned (http://god.rubyforge.org/): Never used it most for this horrible and cryptic config file syntax
And the last one is whatever comes with your linux distrib, init can run an application and restart it when it dies, you have neary no control over it but it can do the job.
You can type "man inittab" to learn more.

How do I start a Rails server programatically from a Ruby script

I want to start my Rails server in a background thread from within a Ruby script. I could use Kernel#system but I want to be able to kill the Rails server when the thread is stopped. Is there a way to execute the Rails server using some Rails API call instead? I'm thinking something it would be nice to be able to put something like Rails.run_server(:port => 3000, ...)
I'm on Windows Server 2008.
Check out the file gems/rails.x.x.x/lib/commands/server.rb. It looks like that's the starting point that script/server uses.
Since script/server is itself a ruby script, it stands to reason that you ought to be able to start a server by doing something similar to what's in server.rb. But I imagine you might have some difficulty getting your ruby environment right...
Note that I'm looking at rails 2.3.8 here, so if you're on 3.whatever your results will probably be different.
I eventually decided to avoid any ickiness and start the rails server in its own process, as detailed in this post. (Being able to kill it plus its child processes consistently was the main blocker and the original reason I'd considered starting it in a thread instead.)

Resources