Important note

This library is in an alpha state and still being developed and tested

ProcessMailer

The idea is simple. Mail data to processes.

What?

The ProcessMailer mails data. To processes. (Oh, it also allows you to send data to hooks, which uses a thread pool and doesn’t restrict memory access, but that’s not the point of this library!) So, the better question might be, why? Well, for one, you can make things faster. See, what’s great about this library is that you encapsulate your logic in little processes that have been forked. Data is then packaged up and sent to these processes where the processes can then do what ever they please to that piece of data. This simple design, though some what more complicated in use, allows you to make use of multiple cpus/cores where using something like a thread pool would keep you limited to a single core.

How does it work?

Well, the general overview is something like this:

Main<||>---------PostOffice<>----------*Postbox

In crappy, texty, UMLy fashion, what we have is a Main program composed of a PostOffice. That PostOffice has an aggregation of zero or more Postboxes it knows about. That’s the basic structure.

How about an example?

Sure, lets make something simple. We will start out using blocks:

require 'processmailer'

po = ProcessMailer::PostOffice.new
po.register{|a| puts "Decrement: #{a}"; a -= 1; a}
po.register{|a| puts "Increment: #{a}"; a += 1; a}

po.deliver(1)
sleep(2)
po.clean

First, we create our PostOffice. Next, we register two Postboxes using blocks. The argument is the Object that will be delivered via the PostOffice. After registering two Postboxes, we deliver a Fixnum. The PostOffice delivers messages to registered Postboxes using a thread pool, so our main line of execution will continue. So, lets sleep for a couple seconds to see some output generated. Finally, we clean the PostOffice which removes all registered Postboxes.

Blocks suck

Well, not really, but they can be a bit restrictive. For something a little more robust, we create a class that’s a subclass of Postbox, and let it do the work:

require 'processmailer'

class Test < ProcessMailer::Postbox
    def initialize(args)
        super
        @foo = 2
    end
    def process(obj)
        puts "Decrement: #{obj}"
        obj -= @foo
    end
end

po = ProcessMailer::PostOffice.new
po.register(Test)
po.register{|a| puts "Increment: #{a}"; a += 1; a}

po.deliver(1)
sleep(2)
po.clean

This is doing the same basic thing we did in the blocks. The Test class is simply a subclass of Postbox, and the process method is overridden to do the grunt work. The reason we send in a Class type, and not the instantiated object, is to allow the PostOffice to do the proper creation and forking. That’s pretty much it.

One last thing

The result of the process method or block for a given Postbox will be returned to the PostOffice for delivery. That is why the examples run continuously. Returning a nil value will stop delivery. This means that the example below will only output two lines:

require 'processmailer'

po = ProcessMailer::PostOffice.new
po.register{|a| puts "Decrement: #{a}"; nil}
po.register{|a| puts "Increment: #{a}"; nil}

po.deliver(1)
sleep(2)
po.clean

ASCII Representation:

[PostOffice]------[message]---->[Postbox]
      ^                             |
      -----------[return val]-------'

Informations

Author: spox <[email protected]>
License: LGPLv3