QRPC ==== **QRPC** currently implements queued JSON-RPC both client and server which works as normal RPC server, but through queue interface, so allows highly scalable, distributed and asynchronous remote API implementation and fast data processing. It's based on [eventmachine][1] and the default implementation uses [beanstalkd][2] so it's fast and thread safe. ### Protocol It utilizes [JSON-RPC][3] protocol by default in versions both [1.1][4] and [2.0][5] altthough different protocols can be implemented. Adds special data member `qrpc` with few options appropriate for queue processing. Typicall request looks in Ruby hash notation like: { "jsonrpc" => "2.0", "method" => "subtract", "params" => [2, 1], "id" => , "qrpc" => { "version" => "1.0", "client" => , "priority" => 30 } } The last `priority` member is optional, others are expected to be present including them which are optional in classic JSON-RPC. Default priority is 50. Typical response looks like: { "jsonrpc" => "2.0", "result" => 1, "id" => , "qrpc" => { "version" => "1.0", } } And in case of exception: { "jsonrpc" => "2.0", "error" => { "code" => , "message" => , "data" => { "name" => , "message" => , "backtrace" => , "dump" => { "raw" => , "format" => "ruby" } } }, "id" => , "qrpc" => { "version" => "1.0", } } Both `backtrace` and `dump` members are optional. ### Variety of Platforms #### Transfer Agents (“Queues”) QRPC uses the [Unified Queues][10] interface which ensures connecting to different queue interfaces using an unified API. It can be used on all platforms which have unified queues driver available by this way. By default, two of them are available: * [beanstalkd][2] queue protocol, * 8 different queues-like in-memory objects (in fact, all priority queue implementations available for Ruby to date). See the [Unified Queues][10] documentation. #### Communication Protocols (“Protocols”) Different protocols can be implemented provided that it will provide the required API. By default, two of them are available: * [JSON-RPC][3] protocol (default, see description above), * object protocol (in fact, the pure Ruby objects for in-memory communication) #### Identification Generators (“Generators”) The request identificators can be generated by various ways. It's possible to implement an own generator so have benefits for logging or in corporate use. By default two generators are available: * [UUID][11] generator (default), * [Ruby object ID][12] generator (fast, intended for in-memory communication in single Ruby instance). #### Encoding Agents (“Serializers”) The JSON-RPC protocol is intended for use with the [JSON][13] encoding, but can be encoded by various other methods. Various serializers support is part of the [JSON-RPC Objects][13] gem. See its documentation. The following protocols are supported for example, to date: * [JSON][14] * [BSON][15] * [YAML][16] * [MessagePack][17] ### Server Usage Usage is simple. Look example of *Beanstalked* *JSON-RPC* service encoded by the *MsgPack* format working *synchronously*: require "qrpc/server" # server require "qrpc/locator/em-jack" # queue transfer agent require "qrpc/protocol/json-rpc" # RPC protocol require "json-rpc-objects/serializer/msgpack" # serializer class Foo def subtract(x, y) x - y end end serializer = JsonRpcObjects::Serializer::MsgPack::new protocol = QRPC::Protocol::JsonRpc::new(:serializer => serializer) locator = QRPC::Locator::EMJackLocator::new("test") server = QRPC::Server::new(Foo::new, :synchronous, protocol) server.listen! locator This creates an instance of `Foo` which will serve as API, creates locator of the queue *test* at default server *localhost:11300*. Queue name will be remapped to the real name *qrpc-test-input*. After call to `#listen!`, it will run eventmachine and start listening for calls. If you want to run it inside already run eventmachine, simply call `#start_listening` with the same parameters. Calls processing is thread safe because of eventmachine concept similar to fibers. Reponse will be put to the same queue server, to queue named `qrpc--output`, with structure described above. Server can work by synchronous or asynchronous way. In the first case, sends the returned values as result, in the other case yielded. ### Client Usage Client usage is simple too. Look example complement the example above: require "eventmachine" require "qrpc/client" # client require "qrpc/generator/uuid" # ID generator require "qrpc/locator/em-jack" # queue transfer agent require "qrpc/protocol/json-rpc" # RPC protocol require "json-rpc-objects/serializer/msgpack" # serializer EM::run do generator = QRPC::Generator::ObjectID::new locator = QRPC::Locator::EMJackLocator::new(:test) serializer = JsonRpcObjects::Serializer::JSON::new protocol = QRPC::Protocol::JsonRpc::new(:serializer => serializer) client = QRPC::Client::new(locator, generator, protocol) client.subtract(2, 3) { |result| puts result } # prints out -1 end This connects to the *test* queue at default server *localhost:11300*, puts request to the real queue name *qrpc-test-input* and waits and then prints the result from `qrpc--output` queue. In case of multiple requests should be noted, results can arrive in any order because, of sure, QRPC is pseudo-fibered and asynchronous from its principle. Client is implemented as [evented][1] too, but in case of need you can implement another one with non-evented interface using whatever [beanstalkd][2] client you like of sure or any other transfer agent. Contributing ------------ 1. Fork it. 2. Create a branch (`git checkout -b 20101220-my-change`). 3. Commit your changes (`git commit -am "Added something"`). 4. Push to the branch (`git push origin 20101220-my-change`). 5. Create an [Issue][6] with a link to your branch. 6. Enjoy a refreshing Diet Coke and wait. Copyright --------- Copyright © 2011-2012 [Martin Kozák][7]. See `LICENSE.txt` for further details. [1]: http://rubyeventmachine.com/ [2]: http://kr.github.com/beanstalkd/ [3]: http://en.wikipedia.org/wiki/JSON-RPC [4]: http://groups.google.com/group/json-rpc/web/json-rpc-1-1-alt [5]: http://groups.google.com/group/json-rpc/web/json-rpc-2-0 [6]: http://github.com/martinkozak/qrpc/issues [7]: http://www.martinkozak.net/ [10]: http://github.com/martinkozak/unified-queues [11]: http://en.wikipedia.org/wiki/Universally_unique_identifier [12]: http://ruby-doc.org/core-1.9.3/Object.html#method-i-object_id [13]: http://github.com/martinkozak/json-rpc-objects [14]: http://www.json.org/ [15]: http://bsonspec.org/ [16]: http://yaml.org/ [17]: http://msgpack.org/