Project

donkey

0.01
No commit activity in last 3 years
No release in over 3 years
Asynchronous Service Stages for Distributed Services
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

>= 0
 Project Readme

Asynchronous Service Stages (ASS) is a way to
organize distributed services by decoupling the
what and how of computation from the when and
where. Built on top of RabbitMQ (an implementation
of AMQP), ASS helps you to build robust and
scalable distributed applications.

End of project pimping, let’s get started.

Install

You need

(1) Erlang
(2) RabbitMQ
(3) AMQP gem

Thread.new { EM.run }
AMQP.start

^C to exit

The Basics

A service component is a ruby script that
communicates with RabbitMQ. You need to define the
AMQP server your ASS depends on. Something like this,

require ‘rubygems’
require ‘ass’
AMQP.start(:host => ‘localhost’,
#:vhost => “/ass-test”,
:logging => false) do

  1. ASS definition
    end

To start a server

server = ASS.new(“echo”)

  1. => #

But it doesn’t do anything yet. You define the
behaviour of the server by setting its
callback. The callback can be a class, so that for
each client request an object is created from the
class to process the request. Like so,

server.react(SomeReactorClass)

However, often you just want something simple. The
react method can take a block and construct an
anonymous callback class from which the server
creates an callback object for each request. Here
we ask the server to react to foo or bar.

server.react {
def foo(input)
[:server,:foo,input]
end

def oof(input) [:server,:oof,input] end

}

The react method accepts for the callback either
a Class, a Module, a block, or any object. When an
object is used, it’s considered a singleton, which
is used to process all the requests.

Now that we have a server, we need to get a client
so to call the server. Because the call is
asynchronous (the client doesn’t wait for the
result), to process the result when it gets back,
we need to define callback for the client (just as
we did for the server). For each call to the
remote server, the result is processed at the
client side by a method of the same name,

client = server.client.react {
def foo(output)
p [:client,:foo,output]
end
def oof(output)
p [:client,:oof,output]
end
}

c.call(:foo,42)
c.call(:oof,24)

  1. [:client,:foo,[:server,:foo,42]]
  2. [:client,:foo,[:server,:foo,24]]

> ruby server.rb
> ruby client.rb

> ruby server.rb
^C

While the server is down, the requests the client
is making is queued by the underlying message
middleware (RabbitMQ), so in some future time when
we restart the server, we wouldn’t lose any
request. Let’s restart the server.

> ruby server.rb

See that the server caught up with all the pending
requests. To increase service capacity, we can
just increase the number of server instances.

> ruby server.rb

Now the load is distributed between these two
instances. We can also start more clients to
handle more load.

> ruby client.rb

You can see requests coming in from two clients.

Service Configuration

-how the name of a service map to AMQP entities.
-various options for different functional characteristics.

-using routing_key
-using reply_to

rabbitmqctl list_exchanges
rabbitmqctl list_queues

RPC service

The RPC client provides a synchronous API to the
asynchronous services. This is so the users of an
ASS application don’t have to bother with the
difficulties of asynchronous programming style
with callbacks.

The RPC client is intended to be used as the
gateway into some reliable internal
services. While the internal services coordinated
with ASS needs to be robust to component failures,
there’s no such requirements for gateways. It is
ok for a gateway to fail, and fail in delivering a
response, as long as the internal services carry
out the task without a hitch.