Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: neglectedvalue/yup
base: 2a83881c0e
...
head fork: neglectedvalue/yup
compare: v0.2.1
  • 9 commits
  • 12 files changed
  • 0 commit comments
  • 1 contributor
View
19 README.rdoc
@@ -9,18 +9,21 @@ This is the small daemon to forward HTTP requests when response is known or unim
When a http request is arrived the yup daemon (yupd), it answers 200 OK (customizable). Then the yupd forwards the http request to the specified host and retries if a timeout error was happend.
== Non-persistent queue
-By default, nonpersistent queue is used. A limit (the option --watermark) at which new concurrent requests will be dropped.
+By default, no persistence is used and forwarded requests is not serialized. A limit (the option --watermark) at which new concurrent requests will be dropped.
== Persistent queue
-If you want use persistent queue you need to specify the option --persistent with a path to a database.
+If you want use persistent queue you need to specify the option --persistent with uri.
== One of use cases
For example we can have a rails app which send exceptions to an Errbit by the gem airbrake. We know the errbit can be not available by network issues or some else reasons, but we do not want to lose exceptions. To resolve this problem we can start yupd on the same host with the rails app:
- yupd --listen localhost:8081 --status-code 201 --persistent /var/db/yupd-errbit errbit.host.somewhere
+ yupd --listen localhost:8081 --status-code 201 --persistent bdb:///var/db/yupd-errbit errbit.host.somewhere
-Reconfiguration of hoptoad_notifier is very ease:
- HoptoadNotifier.configure do |config|
+Or if you have Redis:
+ yupd --listen localhost:8081 --status-code 201 --persistent redis://localhost/yupd-errbit errbit.host.somewhere
+
+Reconfiguration of airbrake gem is very ease:
+ Airbrake.configure do |config|
config.host = "localhost" # yupd host
config.port = 8081 # yupd port
config.api_key = "api_key_for_your_app"
@@ -32,8 +35,8 @@ Now problem of availability errbit is assigned to the yupd.
Feel free to contribute.
-== Copyright
+== Credits
-Copyright (c) 2011 Denis Sukhonin. See LICENSE.txt for
-further details.
+Yup is maintained and funded by {Denis Sukhonin}[mailto:d.sukhonin@gmail.com].
+Thank you to all {the contributors}[https://github.com/neglectedvalue/yup/contributors]!
View
2  VERSION
@@ -1 +1 @@
-0.1.3
+0.2.1
View
59 lib/yup.rb
@@ -1,3 +1,4 @@
+require 'uri'
require 'rubygems'
require 'eventmachine'
require 'logger'
@@ -7,6 +8,7 @@
require 'yup/version'
require 'yup/request_forwarder'
require 'yup/request_handler'
+require 'yup/state'
module Yup
@@resend_delay = 60.0
@@ -26,8 +28,8 @@ def self.retry_unless_2xx; @@retry_unless_2xx end
def self.retry_unless_2xx=(bool); @@retry_unless_2xx = bool end
def self.run(config)
- host = config[:listen_host] || 'localhost'
- port = config[:listen_port] || 8080
+ host = config[:listen_host] || 'localhost'
+ port = config[:listen_port] || 8080
status_code = config[:status_code] || 200
forward_to = config[:forward_to]
timeout = config[:timeout] || 60
@@ -39,7 +41,18 @@ def self.run(config)
end
def self.run_with_state(config)
- require 'yup/state'
+ case State.queue_type(config[:persistent])
+ when :bdb
+ self.run_with_bdb(config)
+ when :redis
+ self.run_with_redis(config)
+ else
+ abort "Unknown scheme of persistent queue."
+ end
+ end
+
+ def self.run_with_bdb(config)
+ require 'yup/state/bdb'
host = config[:listen_host] || 'localhost'
port = config[:listen_port] || 8080
@@ -48,17 +61,17 @@ def self.run_with_state(config)
dbpath = config[:persistent]
timeout = config[:timeout] || 60
feedback_channel = File.join(Dir.tmpdir, "yupd-#{$$}-feedback")
- state = Yup::State.new(dbpath, forward_to, feedback_channel)
+ state = State::BDB.new(dbpath, forward_to, feedback_channel)
pid = Process.fork do
- State::RequestForwarder.new(state, forward_to, timeout).run_loop
+ State::BDB::RequestForwarder.new(state, forward_to, timeout).run_loop
end
if pid
db_closer = proc do
Yup.logger.info { "Terminating consumer #{$$}" }
Process.kill("KILL", pid)
- state.close
+ state.dispose()
exit 0
end
Signal.trap("TERM", &db_closer)
@@ -66,11 +79,43 @@ def self.run_with_state(config)
end
EM.run do
- EM.start_unix_domain_server(feedback_channel, State::FeedbackHandler, state)
+ EM.start_unix_domain_server(feedback_channel, State::BDB::FeedbackHandler, state)
logger.info { "Feedback through #{feedback_channel}" }
EM.start_server(host, port, RequestHandler, forward_to, status_code, state, timeout)
logger.info { "Listening on #{host}:#{port}" }
end
end
+
+ def self.run_with_redis(config)
+ require 'yup/state/redis'
+
+ host = config[:listen_host] || 'localhost'
+ port = config[:listen_port] || 8080
+ status_code = config[:status_code] || 200
+ forward_to = config[:forward_to]
+ dbpath = config[:persistent]
+ timeout = config[:timeout] || 60
+ state = State::Redis.new(dbpath, forward_to)
+
+ pid = Process.fork do
+ State::Redis::RequestForwarder.new(state, forward_to, timeout).run_loop
+ end
+
+ if pid
+ db_closer = proc do
+ Yup.logger.info { "Terminating consumer #{$$}" }
+ Process.kill("KILL", pid)
+ state.dispose()
+ exit 0
+ end
+ Signal.trap("TERM", &db_closer)
+ Signal.trap("INT", &db_closer)
+ end
+
+ EM.run do
+ EM.start_server(host, port, RequestHandler, forward_to, status_code, state, timeout)
+ logger.info { "Listening on #{host}:#{port}" }
+ end
+ end
end
View
128 lib/yup/request_forwarder.rb
@@ -67,132 +67,4 @@ def log_response(http)
end
end
end
-
- class State
- class RequestForwarder
- def initialize(state, forward_to, timeout)
- @state = state
- @forward_to = forward_to
- @timeout = timeout
- @logger = Yup.logger.clone
- @logger.progname = "Yup::State::RequestForwarder"
-
- @yajl = Yajl::Parser.new(:symbolize_keys => true)
- @yajl.on_parse_complete = self.method(:make_request)
- end
-
- def run_loop
- loop do
- data = @state.bpop
- begin
- @yajl << data
- rescue Yajl::ParseError
- @logger.error { "Error while parsing \"#{data}\"" }
- end
- end
- end
-
- def make_request(req)
- begin
- @http_method, @request_url, headers, body = req
- headers = Hash[*headers.to_a.flatten.map(&:to_s)]
- headers["Host"] = @forward_to
- headers["Connection"] = "Close"
-
- req = "#{@http_method.upcase} #{@request_url} HTTP/1.1\r\n"
- headers.each do |k, v|
- req << "#{k}: #{v}\r\n"
- end
- req << "\r\n"
- req << body if !body.empty?
- raw_response = send_data(req.to_s, @forward_to)
-
- response_body = ""
- http = Http::Parser.new()
- http.on_body = proc do |chunk|
- response_body << chunk
- end
- http << raw_response
-
- if http.status_code && http.status_code / 100 == 2
- log_response(raw_response, response_body, http)
- @logger.info "Success"
- else
- log_response(raw_response, response_body, http)
- if Yup.retry_unless_2xx
- @logger.info "Fail: got status code #{http.status_code}; will retry after #{Yup.resend_delay} seconds"
- @state.to_feedback(Yajl::Encoder.encode([@http_method.downcase, @request_url, headers, body]))
-
- sleep Yup.resend_delay
- else
- @logger.info "Fail; will not retry"
- end
- end
-
- rescue Exception, Timeout::Error => e
- log_response(raw_response, response_body, http)
- @logger.info "Error: #{e.class}: #{e.message}; will retry after #{Yup.resend_delay} seconds"
-
- @state.to_feedback(Yajl::Encoder.encode([@http_method.downcase, @request_url, headers, body]))
-
- sleep Yup.resend_delay
- end
- end
-
- private
- def log_response(raw_response, body, http)
- @logger.info { "HTTP request: #{@http_method.upcase} #{@request_url} HTTP/1.1" }
- if raw_response && !raw_response.empty?
- @logger.info { "HTTP response: #{raw_response.lines.first.chomp}" }
- @logger.debug { "HTTP response headers" + (http.headers.empty? ? " is empty" : "\n" + http.headers.inspect) }
- @logger.debug { "HTTP response body" + (body.empty? ? " is empty" : "\n" + body.inspect) }
- end
- end
-
- def send_data(data, host)
- host, port = host.split(":")
- addr = Socket.getaddrinfo(host, nil)
- sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
-
- secs = Integer(@timeout)
- usecs = Integer((@timeout - secs) * 1_000_000)
- optval = [secs, usecs].pack("l_2")
- sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval)
- sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval)
-
- resp = Timeout::timeout(@timeout) do
- sock.connect(Socket.pack_sockaddr_in(port, addr[0][3]))
- sock.write(data)
- sock.read()
- end
- return resp
- ensure
- sock.close()
- end
- end
-
- class FeedbackHandler < EM::Connection
- def initialize(state)
- @state = state
-
- @yajl = Yajl::Parser.new(:symbolize_keys => true)
- @yajl.on_parse_complete = method(:on_message)
-
- @logger = Yup.logger.clone
- @logger.progname = "Yup::State::FeedbackHandler"
- end
-
- def receive_data(data)
- begin
- @yajl << data
- rescue Yajl::ParseError
- @logger.error { "Error while parsing \"#{data}\"" }
- end
- end
-
- def on_message(req)
- @state.push(Yajl::Encoder.encode(req))
- end
- end
- end
end
View
149 lib/yup/state.rb
@@ -1,64 +1,115 @@
-begin
- require 'bdb'
- require 'bdb/database'
-rescue LoadError
- puts "Install bdb gem to use a persistent queue."
-end
+module Yup
+ module State
+ def self.queue_type(str)
+ uri = URI.parse(str)
+ case uri.scheme
+ when "bdb"
+ :bdb
+ when "redis"
+ :redis
+ end
+ end
-require "timeout"
+ class RequestForwarder
+ def initialize(state, forward_to, timeout)
+ @state = state
+ @forward_to = forward_to
+ @timeout = timeout
+ @logger = Yup.logger.clone
+ @logger.progname = "Yup::State::RequestForwarder"
-module Yup
- class State
- RE_LEN = 1000
+ @yajl = Yajl::Parser.new(:symbolize_keys => true)
+ @yajl.on_parse_complete = self.method(:make_request)
+ end
- attr_reader :queue
+ def run_loop
+ loop do
+ data = @state.bpop
+ begin
+ @yajl << data
+ rescue Yajl::ParseError
+ @logger.error { "Error while parsing \"#{data}\"" }
+ end
+ end
+ end
- def self.repair_if_need(path)
- env = Bdb::Env.new(0)
- env.open(path, Bdb::DB_CREATE | Bdb::DB_INIT_TXN | Bdb::DB_RECOVER, 0)
- env.close()
- end
+ def make_request(req)
+ begin
+ @http_method, @request_url, headers, body = req
+ headers = Hash[*headers.to_a.flatten.map(&:to_s)]
+ headers["Host"] = @forward_to
+ headers["Connection"] = "Close"
- def initialize(path, name, feedback_channel)
- @path = path
- @name = name
- @feedback_channel = feedback_channel
+ req = "#{@http_method.upcase} #{@request_url} HTTP/1.1\r\n"
+ headers.each do |k, v|
+ req << "#{k}: #{v}\r\n"
+ end
+ req << "\r\n"
+ req << body if !body.empty?
+ raw_response = send_data(req.to_s, @forward_to)
- @logger = Yup.logger.clone
- @logger.progname = "Yup::State"
+ response_body = ""
+ http = Http::Parser.new()
+ http.on_body = proc do |chunk|
+ response_body << chunk
+ end
+ http << raw_response
- FileUtils.mkdir_p(@path)
- @env = Bdb::Env.new(0)
- @env = @env.open(@path, Bdb::DB_CREATE | Bdb::DB_INIT_MPOOL | Bdb::DB_INIT_CDB, 0)
- @queue = @env.db
- @queue.re_len = RE_LEN
- @queue.open(nil, @name, nil, Bdb::Db::QUEUE, Bdb::DB_CREATE, 0)
- end
+ if http.status_code && http.status_code / 100 == 2
+ log_response(raw_response, response_body, http)
+ @logger.info "Success"
+ else
+ log_response(raw_response, response_body, http)
+ if Yup.retry_unless_2xx
+ @logger.info "Fail: got status code #{http.status_code}; will retry after #{Yup.resend_delay} seconds"
+ @state.pushback(Yajl::Encoder.encode([@http_method.downcase, @request_url, headers, body]))
- def push(data)
- @logger.debug { "Push: #{data}" }
- i = 0
- until (chunk = data.slice(i, RE_LEN)).nil?
- @queue.put(nil, "", chunk, Bdb::DB_APPEND)
- i += @queue.re_len
+ sleep Yup.resend_delay
+ else
+ @logger.info "Fail; will not retry"
+ end
+ end
+
+ rescue Exception, Timeout::Error => e
+ log_response(raw_response, response_body, http)
+ @logger.info "Error: #{e.class}: #{e.message}; will retry after #{Yup.resend_delay} seconds"
+
+ @state.pushback(Yajl::Encoder.encode([@http_method.downcase, @request_url, headers, body]))
+
+ sleep Yup.resend_delay
+ end
end
- end
- def bpop
- data = @queue.get(nil, "", nil, Bdb::DB_CONSUME_WAIT)
- @logger.debug { "Bpoped: #{data.strip}" }
- data
- end
+ private
+ def log_response(raw_response, body, http)
+ @logger.info { "HTTP request: #{@http_method.upcase} #{@request_url} HTTP/1.1" }
+ if raw_response && !raw_response.empty?
+ @logger.info { "HTTP response: #{raw_response.lines.first.chomp}" }
+ @logger.debug { "HTTP response headers" + (http.headers.empty? ? " is empty" : "\n" + http.headers.inspect) }
+ @logger.debug { "HTTP response body" + (body.empty? ? " is empty" : "\n" + body.inspect) }
+ end
+ end
- def to_feedback(data)
- @logger.debug { "Push to the feedback channel: #{data.strip}" }
- sock = UNIXSocket.new(@feedback_channel)
- sock.send(data, 0)
- sock.close
- end
+ def send_data(data, host)
+ host, port = host.split(":")
+ addr = Socket.getaddrinfo(host, nil)
+ sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
- def close
- @queue.close(0)
+ secs = Integer(@timeout)
+ usecs = Integer((@timeout - secs) * 1_000_000)
+ optval = [secs, usecs].pack("l_2")
+ sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval)
+ sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval)
+
+ resp = Timeout::timeout(@timeout) do
+ sock.connect(Socket.pack_sockaddr_in(port, addr[0][3]))
+ sock.write(data)
+ sock.read()
+ end
+ return resp
+ ensure
+ sock.close()
+ end
end
end
end
View
99 lib/yup/state/bdb.rb
@@ -0,0 +1,99 @@
+begin
+ require 'bdb'
+ require 'bdb/database'
+rescue LoadError
+ abort "Install bdb gem to use a persistent queue."
+end
+
+require "timeout"
+
+module Yup
+ module State
+ class BDB
+ RE_LEN = 1000
+
+ attr_reader :queue
+
+ def self.repair_if_need(path)
+ env = Bdb::Env.new(0)
+ env.open(path, Bdb::DB_CREATE | Bdb::DB_INIT_TXN | Bdb::DB_RECOVER, 0)
+ env.close()
+ end
+
+ def initialize(uri, forward_to, feedback_channel)
+ @uri = URI.parse(uri)
+ @path = @uri.path
+ @name = forward_to
+ @feedback_channel = feedback_channel
+
+ @logger = Yup.logger.clone
+ @logger.progname = "Yup::State::BDB"
+
+ FileUtils.mkdir_p(@path)
+ @env = Bdb::Env.new(0)
+ @env = @env.open(@path, Bdb::DB_CREATE | Bdb::DB_INIT_MPOOL | Bdb::DB_INIT_CDB, 0)
+ @queue = @env.db
+ @queue.re_len = RE_LEN
+ @queue.open(nil, @name, nil, Bdb::Db::QUEUE, Bdb::DB_CREATE, 0)
+ end
+
+ def push(data)
+ @logger.debug { "Push: #{data}" }
+ i = 0
+ until (chunk = data.slice(i, RE_LEN)).nil?
+ @queue.put(nil, "", chunk, Bdb::DB_APPEND)
+ i += @queue.re_len
+ end
+ end
+
+ def bpop
+ data = @queue.get(nil, "", nil, Bdb::DB_CONSUME_WAIT)
+ @logger.debug { "Bpoped: #{data.strip}" }
+ data
+ end
+
+ def pushback(data)
+ @logger.debug { "Push to the feedback channel: #{data.strip}" }
+ sock = UNIXSocket.new(@feedback_channel)
+ sock.send(data, 0)
+ sock.close
+ end
+
+ def dispose
+ @queue.close(0)
+ end
+
+ class RequestForwarder < ::Yup::State::RequestForwarder
+ def initialize(*args)
+ super
+ @logger = Yup.logger.clone
+ @logger.progname = "Yup::State::BDB::RequestForwarder"
+ end
+ end
+
+ class FeedbackHandler < EM::Connection
+ def initialize(state)
+ @state = state
+
+ @yajl = Yajl::Parser.new(:symbolize_keys => true)
+ @yajl.on_parse_complete = method(:on_message)
+
+ @logger = Yup.logger.clone
+ @logger.progname = "Yup::State::BDB::FeedbackHandler"
+ end
+
+ def receive_data(data)
+ begin
+ @yajl << data
+ rescue Yajl::ParseError
+ @logger.error { "Error while parsing \"#{data}\"" }
+ end
+ end
+
+ def on_message(req)
+ @state.push(Yajl::Encoder.encode(req))
+ end
+ end
+ end
+ end
+end
View
52 lib/yup/state/redis.rb
@@ -0,0 +1,52 @@
+begin
+ require 'redis'
+ require 'redis-namespace'
+rescue LoadError
+ abort "Install redis-namespace gem to use a persistent queue."
+end
+
+module Yup
+ module State
+ class Redis
+ def initialize(uri, forward_to)
+ @uri = URI.parse(uri)
+ @ns = @uri.path[1..-1]
+ @ns = "yup-#{VERSION}" if @ns.empty?
+ @ns << ":#{forward_to}"
+
+ @logger = Yup.logger.clone
+ @logger.progname = "Yup::State::Redis"
+
+ @redis_backend = ::Redis.new(:host => @uri.host, :port => @uri.port)
+ @redis = ::Redis::Namespace.new(@ns, :redis => @redis_backend)
+ end
+
+ def push(data)
+ @logger.debug { "Push: #{data}" }
+ @redis.lpush("requests", data)
+ end
+
+ def pushback(data)
+ @logger.debug { "Push back: #{data}" }
+ @redis.lpush("requests", data)
+ end
+
+ def bpop
+ _, data = @redis.brpop("requests", :timeout => 0)
+ @logger.debug { "Bpoped: #{data.strip}" }
+ data
+ end
+
+ def dispose
+ end
+
+ class RequestForwarder < ::Yup::State::RequestForwarder
+ def initialize(*args)
+ super
+ @logger = Yup.logger.clone
+ @logger.progname = "Yup::State::Redis::RequestForwarder"
+ end
+ end
+ end
+ end
+end
View
63 test/helper.rb
@@ -28,7 +28,68 @@ def format(result)
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'yup'
-class MiniTest::Unit::TestCase
+class YupTestCase < MiniTest::Unit::TestCase
+ def after_setup
+ Service.attempts = 0
+ super
+ end
+
+ class Service < EM::Connection
+ @@attempts = 0
+ def self.attempts; @@attempts end
+ def self.attempts=(n); @@attempts = n end
+
+ def post_init
+ @parser = Http::Parser.new(self)
+ end
+
+ def receive_data(data)
+ @parser << data
+ end
+
+ def on_message_complete
+ $service_parser = @parser
+
+ case @@attempts
+ when 0
+ when 1
+ send_data "HTTP/1.1 400 Bad Request\r\nServer: test\r\n\r\n"
+ close_connection_after_writing
+ when 2
+ send_data "HTTP/1.1 200 OK\r\nServer: test\r\n\r\n"
+ close_connection_after_writing
+ end
+
+ @@attempts += 1
+ end
+
+ def unbind
+ if @@attempts > 2
+ EM.add_timer(1) do
+ Process.kill("KILL", $pid)
+ EM.stop_event_loop()
+ end
+ end
+ end
+ end
+
+ module Client
+ def connection_completed
+ send_data("GET /foo HTTP/1.0\r\n\r\n")
+ end
+
+ def post_init
+ @parser = Http::Parser.new(self)
+ end
+
+ def receive_data(data)
+ @parser << data
+ end
+
+ def on_message_complete
+ $client_parser = @parser
+ end
+ end
end
MiniTest::Unit.autorun
View
105 test/test_persistence_yup.rb
@@ -1,105 +0,0 @@
-require 'helper'
-
-require 'tmpdir'
-require 'fileutils'
-require 'yup/state'
-
-class Yup::State::FeedbackHandler
- alias :on_message_original :on_message
- def on_message(req)
- on_message_original(req)
- $attempts += 1
- end
-end
-
-class TestPersistenceYup < MiniTest::Unit::TestCase
- class RequestHandlerMock < Yup::RequestHandler
- end
-
- class Service < EM::Connection
- def post_init
- @parser = Http::Parser.new(self)
- end
-
- def receive_data(data)
- @parser << data
- end
-
- def on_message_complete
- $service_parser = @parser
-
- case $attempts
- when 0
- when 1
- send_data "HTTP/1.1 400 Bad Request\r\nServer: test\r\n\r\n"
- close_connection_after_writing
- when 2
- send_data "HTTP/1.1 200 OK\r\nServer: test\r\n\r\n"
- close_connection_after_writing
- end
- end
-
- def unbind
- if $attempts >= 2
- EM.add_timer(1) do
- Process.kill("KILL", $pid)
- EM.stop_event_loop()
- end
- end
- end
- end
-
- module Client
- def connection_completed
- send_data("GET /foo HTTP/1.0\r\n\r\n")
- end
-
- def post_init
- @parser = Http::Parser.new(self)
- end
-
- def receive_data(data)
- @parser << data
- end
-
- def on_message_complete
- $client_parser = @parser
- end
- end
-
- def test_request_handler
- $attempts = 0
-
- dbpath = Dir.mktmpdir("yupd-db")
- feedback_channel = File.join(Dir.tmpdir, "yupd-#{$$}-feedback")
-
- forward_to = "127.0.0.1:26785"
- status_code = 200
- state = Yup::State.new(dbpath, forward_to, feedback_channel)
- timeout = 1
-
- Yup.resend_delay = 1
- Yup.retry_unless_2xx = true
-
- $pid = Process.fork do
- Yup::State::RequestForwarder.new(state, forward_to, timeout).run_loop
- end
-
- EM.run {
- EM.start_server("127.0.0.1", 26785, Service)
- EM.start_unix_domain_server(feedback_channel, Yup::State::FeedbackHandler, state)
- EM.start_server("127.0.0.1", 26784, RequestHandlerMock, forward_to, status_code, state, timeout)
- EM.connect("127.0.0.1", 26784, Client)
- }
-
- assert $client_parser
- assert_equal 200, $client_parser.status_code
- assert_equal "yupd", $client_parser.headers["Server"]
- assert $service_parser
- assert_equal "/foo", $service_parser.request_url
- ensure
- Process.kill("KILL", $pid) if $pid
- state.close if state
- FileUtils.remove_entry_secure(dbpath) if dbpath
- end
-end
View
47 test/test_stateful_yup_with_bdb.rb
@@ -0,0 +1,47 @@
+require 'helper'
+
+require 'tmpdir'
+require 'fileutils'
+require 'yup/state/bdb'
+
+class TestStatefulYupWithBDB < YupTestCase
+ class RequestHandlerMock < Yup::RequestHandler
+ end
+
+ def test_request_handler
+ Service.attempts = 0
+
+ dbpath = Dir.mktmpdir("yupd-db")
+ uri = "bdb://#{dbpath}"
+ feedback_channel = File.join(Dir.tmpdir, "yupd-#{$$}-feedback")
+ forward_to = "127.0.0.1:26785"
+ status_code = 200
+ state = Yup::State::BDB.new(uri, forward_to, feedback_channel)
+ timeout = 1
+
+ Yup.resend_delay = 1
+ Yup.retry_unless_2xx = true
+
+ $pid = Process.fork do
+ Yup::State::BDB::RequestForwarder.new(state, forward_to, timeout).run_loop
+ end
+
+ EM.run {
+ EM.start_server("127.0.0.1", 26785, Service)
+ EM.start_unix_domain_server(feedback_channel, Yup::State::BDB::FeedbackHandler, state)
+ EM.start_server("127.0.0.1", 26784, RequestHandlerMock, forward_to, status_code, state, timeout)
+ EM.connect("127.0.0.1", 26784, Client)
+ }
+
+ assert $client_parser
+ assert_equal 200, $client_parser.status_code
+ assert_equal "yupd", $client_parser.headers["Server"]
+ assert $service_parser
+ assert_equal "/foo", $service_parser.request_url
+ assert_equal 3, Service.attempts
+ ensure
+ Process.kill("KILL", $pid) if $pid
+ state.dispose() if state
+ FileUtils.remove_entry_secure(dbpath) if dbpath
+ end
+end
View
41 test/test_stateful_yup_with_redis.rb
@@ -0,0 +1,41 @@
+require 'helper'
+
+require 'tmpdir'
+require 'fileutils'
+require 'yup/state/redis'
+
+class TestStatefulYupWithRedis < YupTestCase
+ class RequestHandlerMock < Yup::RequestHandler
+ end
+
+ def test_request_handler
+ uri = "redis://localhost/yup-testing-#{Time.now.to_f}"
+ forward_to = "127.0.0.1:26785"
+ status_code = 200
+ state = Yup::State::Redis.new(uri, forward_to)
+ timeout = 1
+
+ Yup.resend_delay = 1
+ Yup.retry_unless_2xx = true
+
+ $pid = Process.fork do
+ Yup::State::Redis::RequestForwarder.new(state, forward_to, timeout).run_loop
+ end
+
+ EM.run {
+ EM.start_server("127.0.0.1", 26785, Service)
+ EM.start_server("127.0.0.1", 26784, RequestHandlerMock, forward_to, status_code, state, timeout)
+ EM.connect("127.0.0.1", 26784, Client)
+ }
+
+ assert $client_parser
+ assert_equal 200, $client_parser.status_code
+ assert_equal "yupd", $client_parser.headers["Server"]
+ assert $service_parser
+ assert_equal "/foo", $service_parser.request_url
+ assert_equal 3, Service.attempts
+ ensure
+ Process.kill("KILL", $pid) if $pid
+ state.dispose() if state
+ end
+end
View
36 yup.gemspec
@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = "yup"
- s.version = "0.1.3"
+ s.version = "0.2.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Denis Sukhonin"]
- s.date = "2013-01-09"
+ s.date = "2013-02-18"
s.description = "Just answers 200 (or specified) to a client and asynchronously forwards HTTP request to a configured host"
s.email = "d.sukhonin@gmail.com"
s.executables = ["yupd"]
@@ -31,9 +31,12 @@ Gem::Specification.new do |s|
"lib/yup/request_forwarder.rb",
"lib/yup/request_handler.rb",
"lib/yup/state.rb",
+ "lib/yup/state/bdb.rb",
+ "lib/yup/state/redis.rb",
"lib/yup/version.rb",
"test/helper.rb",
- "test/test_persistence_yup.rb",
+ "test/test_stateful_yup_with_bdb.rb",
+ "test/test_stateful_yup_with_redis.rb",
"test/test_yup.rb",
"yup.gemspec"
]
@@ -53,13 +56,14 @@ Gem::Specification.new do |s|
s.add_runtime_dependency(%q<tuple>, [">= 0"])
s.add_runtime_dependency(%q<yajl-ruby>, [">= 0"])
s.add_development_dependency(%q<bdb>, [">= 0"])
+ s.add_development_dependency(%q<redis-namespace>, [">= 0"])
s.add_development_dependency(%q<yard>, ["~> 0.8.0"])
- s.add_development_dependency(%q<minitest>, [">= 0"])
+ s.add_development_dependency(%q<minitest>, ["~> 4.5"])
s.add_development_dependency(%q<bundler>, ["~> 1.2"])
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
- s.add_development_dependency(%q<simplecov>, [">= 0"])
- s.add_development_dependency(%q<simplecov-rcov>, [">= 0"])
- s.add_development_dependency(%q<travis-lint>, [">= 0"])
+ s.add_development_dependency(%q<simplecov>, ["~> 0.7.1"])
+ s.add_development_dependency(%q<simplecov-rcov>, ["~> 0.2.3"])
+ s.add_development_dependency(%q<travis-lint>, ["~> 1.4"])
else
s.add_dependency(%q<eventmachine>, [">= 0"])
s.add_dependency(%q<em-http-request>, [">= 0"])
@@ -67,13 +71,14 @@ Gem::Specification.new do |s|
s.add_dependency(%q<tuple>, [">= 0"])
s.add_dependency(%q<yajl-ruby>, [">= 0"])
s.add_dependency(%q<bdb>, [">= 0"])
+ s.add_dependency(%q<redis-namespace>, [">= 0"])
s.add_dependency(%q<yard>, ["~> 0.8.0"])
- s.add_dependency(%q<minitest>, [">= 0"])
+ s.add_dependency(%q<minitest>, ["~> 4.5"])
s.add_dependency(%q<bundler>, ["~> 1.2"])
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
- s.add_dependency(%q<simplecov>, [">= 0"])
- s.add_dependency(%q<simplecov-rcov>, [">= 0"])
- s.add_dependency(%q<travis-lint>, [">= 0"])
+ s.add_dependency(%q<simplecov>, ["~> 0.7.1"])
+ s.add_dependency(%q<simplecov-rcov>, ["~> 0.2.3"])
+ s.add_dependency(%q<travis-lint>, ["~> 1.4"])
end
else
s.add_dependency(%q<eventmachine>, [">= 0"])
@@ -82,13 +87,14 @@ Gem::Specification.new do |s|
s.add_dependency(%q<tuple>, [">= 0"])
s.add_dependency(%q<yajl-ruby>, [">= 0"])
s.add_dependency(%q<bdb>, [">= 0"])
+ s.add_dependency(%q<redis-namespace>, [">= 0"])
s.add_dependency(%q<yard>, ["~> 0.8.0"])
- s.add_dependency(%q<minitest>, [">= 0"])
+ s.add_dependency(%q<minitest>, ["~> 4.5"])
s.add_dependency(%q<bundler>, ["~> 1.2"])
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
- s.add_dependency(%q<simplecov>, [">= 0"])
- s.add_dependency(%q<simplecov-rcov>, [">= 0"])
- s.add_dependency(%q<travis-lint>, [">= 0"])
+ s.add_dependency(%q<simplecov>, ["~> 0.7.1"])
+ s.add_dependency(%q<simplecov-rcov>, ["~> 0.2.3"])
+ s.add_dependency(%q<travis-lint>, ["~> 1.4"])
end
end

No commit comments for this range

Something went wrong with that request. Please try again.