RACK-AMQPA NEW RUBY WEBAPP SERVER
WhatRack-AMQP is:
jackalope (rack app server)
amqurl (client with curl syntax)
rack-amqp-client (ruby client lib)
AMQParty (ruby client lib, API-compatible with HTTParty)
Demo
WhatRack-AMQP is:
jackalope (rack app server)
amqurl (client with curl syntax)
rack-amqp-client (ruby client lib)
AMQParty (ruby client lib, API-compatible with HTTParty)
Demo
WHY
SOAMany services communicating with each other
Need direct fetch capabilities (GET, POST), also publish-subscribe
HTTP doesn't do pub/sub
We have all this HTTP infrastructure and code already!
We know HTTP
HTTP in your SOA
seems simple, but it's actually complex
Load Balancers
SSL Everywhere
Fixed IPs or hostnames or service locators
Connection setup / teardown
AMQPOpen standard
Allows any system to connect (Ruby, Java, Haskell, whatever)
Secure by default
Everything is a queue
No load balancing
No fixed locations, just queue names
Persistent connection
HOW
Implements AMQP
Robust messaging for applications
Easy to use
Runs on all major operating systems
Supports a huge number of developer platforms
Open source and commercially supported
AMQP Topologies
Simple-enough config
{ssl_options, [{cacertfile, "/path/to/testca/cacert.pem"}, {certfile, "/path/to/server/cert.pem"}, {keyfile, "/path/to/server/key.pem"}, {verify, verify_peer}, {fail_if_no_peer_cert, false}]},
{default_vhost, <<"/">>}, {default_user, <<"guest">>}, {default_pass, <<"guest">>}, {default_permissions, [<<".*">>, <<".*">>, <<".*">>]},
Simple-enough config
{ssl_options, [{cacertfile, "/path/to/testca/cacert.pem"}, {certfile, "/path/to/server/cert.pem"}, {keyfile, "/path/to/server/key.pem"}, {verify, verify_peer}, {fail_if_no_peer_cert, false}]},
{default_vhost, <<"/">>}, {default_user, <<"guest">>}, {default_pass, <<"guest">>}, {default_permissions, [<<".*">>, <<".*">>, <<".*">>]},
SERVER
The common language for ruby web applications
1 class HelloWorld!2 def call(env)!3 [200, {"Content-Type" => "text/plain"}, ["Hello world!"]]!4 end!5 end
The common language for ruby web applications
1 class HelloWorld!2 def call(env)!3 [200, {"Content-Type" => "text/plain"}, ["Hello world!"]]!4 end!5 end
Response Code Headers Body
Rack-AMQP
#!/usr/bin/env ruby!
require "rack/amqp"!
Rack::AMQP::Server.start rackup_file: File.absolute_path(ARGV[0])
rack-amqp/bin/raqup
class Rack::AMQP::Server! def start! ::AMQP.start(host: 'localhost') do |client|! chan = ::AMQP::Channel.new(client)!! chan.queue("test.simple").subscribe do |metadata, payload|! response, headers = handle_request(metadata, payload)!! message_id = metadata.message_id! reply_to = metadata.reply_to!! amqp_headers = {! routing_key: reply_to, correlation_id: message_id,! type: 'REPLY', app_id: server_agent,! timestamp: Time.now.to_i, headers: headers! }! amqp_headers[:content_type] = type if type = headers['Content-Type']! amqp_headers[:content_encoding] = enc if enc = headers['Content-Encoding']!! chan.direct("").publish(response, amqp_headers)! end!! puts "#{server_agent} running"! end! end!end
AMQP
class Rack::AMQP::Server! def handle_request(meta, body)! headers = meta.headers! http_method = meta.type! path = headers['path']!! parts = path.split(/\?/)! uri = parts[0]! query = parts[1] || ""!! env = default_env! env.update({! 'REQUEST_METHOD' => http_method,! 'PATH_INFO' => uri,! 'QUERY_STRING' => query,! 'REQUEST_PATH' => uri,! })!! response_code, headers, body = app.call(env)!! headers.merge!('X-AMQP-HTTP-Status' => response_code)!! body_chunks = []! body.each { |chunk| body_chunks << chunk }! body.close!! [body_chunks.join, headers]! end!end
Rack
NOT FINISHED!
TODO
Test in staging, test in production
Iron-out performance issues
Load test
Support more curl options for amqurl
Allow config file for jackalope
Thanks!Josh Szmajda
@jszmajda
@rubyhangout
CTO, Optoro
We are hiring ;)
http://www.github.com/joshsz/rack-amqp