Question

So, I have a long-running Ruby process, that does a wide variety of things, depending on what's it told to do (EventMachine TCP server with binary messages). Now, I would like to give certain people the ability to monitor, change, shut down the given process via a web interface. I plan on using Sinatra.rb for that, however I am open to better alternatives.

My original idea was to run the Sinatra web interface (it's based on Rack, for those who're not familiar with Sinatra) inside a Thread and let it run in the background.

However, I was thinking it might impact performance if I do it that way, so I decided to look into IPC abilities and alternative implementations for Ruby (resque, memory sharing, named pipes, etc).

I really liked the idea of resque (and the name is really witty), but I am not entirely sure if it's what I need, or if it may be overkill. Actually, I am not even sure how I would best implement it with Sinatra and EventMachine (although, I didn't read the full documentation for resque, just scanned through it quickly and read the examples and use-cases.).

Another idea that came to mind is using Sinatra inside EventMachine::defer, but isn't that essentially the same as creating a new Thread?

I have never done anything serious using Fibers, so I don't know their full potential, but they did cross my mind.

So, which of those (or suggest a better) practices is the best for Ruby PCI.

Thanks

Was it helpful?

Solution

I would suggest you to use signals to communicate to your running process.

With this approach it wont matter what framework you are using,
though my best recommandation is Espresso Framework.

So here is the deal. There are a lot of signals you can send to your process via kill interface.

Signals can be sent from command line of from another Ruby process.

All you need is to catch/trap sent signal(s) inside your app.

Example: inside controlled process:

# build your app

Signal.trap("USR1") do
  # do some stuff here
end

Signal.trap("USR2") do
  # do another stuff here
end

# run your app

When you start your app make sure to get its PID.

Having the PID you can send signals to your app via kill
(no, it wont kill your app unless you send an explicit signal for this).

Then from another Ruby process you can do:

Process.kill "USR1", PID

Or directly from command line:

kill USR2 PID

And your app will catch/trap send signal and do corresponding stuff.

Just make sure to replace PID with real Process ID of controlled app.

This practice are successfully used by Unicorn web server.

Here is a list of signals:

http://en.wikipedia.org/wiki/Unix_signal

Some insight on working with signals in Ruby:

https://jellyjelly.net/blog/2010/04/27/unix-signal-programming-in-ruby/

OTHER TIPS

You could use a local message queue such as RabbitMQ (an implementation of AMQP) but this is effectively the same as using Redis as you mentioned.

This sort of approach will be not depend on OS specific interprocess communication mechanisms. So yes, you'll be running another service but you won't be coupled to anything low level. This can be a very good thing when it comes time to scale.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top