arya-pandemic 0.4.1 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest CHANGED
@@ -10,6 +10,7 @@ lib/pandemic/client_side/connection_proxy.rb
10
10
  lib/pandemic/client_side/pandemize.rb
11
11
  lib/pandemic/connection_pool.rb
12
12
  lib/pandemic/mutex_counter.rb
13
+ lib/pandemic/requests_per_second.rb
13
14
  lib/pandemic/server_side/client.rb
14
15
  lib/pandemic/server_side/config.rb
15
16
  lib/pandemic/server_side/handler.rb
data/README.markdown CHANGED
@@ -119,6 +119,10 @@ The servers are going to try to bind to localhost:4000 and localhost:4001 so mak
119
119
  By default, the handler runs in the same Ruby process as Pandemic. By setting the fork\_for\_processor to true in pandemic\_server.yml, you can have Pandemic fork to new processes to run the process method. This is particularly useful when your process method goes to MySQL which locks the entire process until MySQL returns.
120
120
 
121
121
  ## Change History
122
+ **Version 0.4.2**
123
+
124
+ * Log file and log level now specify-able as hash attributes to the _epidemic!_ method.
125
+
122
126
  **Version 0.3.1**
123
127
 
124
128
  * Changed map to partition to more accurately reflect what it does. This breaks backwards compatibility, but all you have to do is rename your method.
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('pandemic', '0.4.1') do |p|
5
+ Echoe.new('pandemic', '0.4.3') do |p|
6
6
  p.description = "A framework for distributing work for real-time services and offline tasks."
7
7
  p.url = "https://github.com/arya/pandemic/"
8
8
  p.author = "Arya Asemanfar"
data/lib/pandemic.rb CHANGED
@@ -10,6 +10,7 @@ require 'logger'
10
10
  require 'pandemic/util'
11
11
  require 'pandemic/connection_pool'
12
12
  require 'pandemic/mutex_counter'
13
+ require 'pandemic/requests_per_second'
13
14
 
14
15
  require 'pandemic/server_side/config'
15
16
  require 'pandemic/server_side/client'
@@ -25,22 +26,16 @@ require 'pandemic/client_side/connection'
25
26
  require 'pandemic/client_side/connection_proxy'
26
27
  require 'pandemic/client_side/pandemize'
27
28
 
28
- # TODO:
29
- # - tests
30
- # - IO timeouts/robustness
31
- # - documentation
32
- # - PING/PONG?
33
-
34
29
  TCP_NO_DELAY_AVAILABLE =
35
30
  RUBY_VERSION < '1.9' ? Socket.constants.include?('TCP_NODELAY') : Socket.constants.include?(:TCP_NODELAY)
36
31
 
37
- def epidemic!(bind_to = nil)
32
+ def epidemic!(options = {})
38
33
  if $pandemic_logger.nil?
39
- $pandemic_logger = Logger.new("pandemic.log")
40
- $pandemic_logger.level = Logger::INFO
34
+ $pandemic_logger = Logger.new(options[:log_file] || "pandemic.log")
35
+ $pandemic_logger.level = options[:log_level] || Logger::INFO
41
36
  $pandemic_logger.datetime_format = "%Y-%m-%d %H:%M:%S "
42
37
  end
43
- Pandemic::ServerSide::Server.boot(bind_to)
38
+ Pandemic::ServerSide::Server.boot(options[:bind_to])
44
39
  end
45
40
 
46
41
  ::Pandemize = Pandemic::ClientSide::Pandemize
@@ -0,0 +1,31 @@
1
+ module Pandemic
2
+ class RequestsPerSecond
3
+ def initialize(sample_size = 10)
4
+ @hits = Array.new(sample_size + 2)
5
+ @last_hit_at = nil
6
+ end
7
+
8
+ def hit(now = Time.now.to_i)
9
+ key = now % @hits.size
10
+ if @hits[key].nil? || @hits[key][0] != now
11
+ @hits[key] = [now, 0]
12
+ end
13
+ @hits[key][1] += 1
14
+ @last_hit_at = now
15
+ end
16
+
17
+ def rps(now = Time.now.to_i)
18
+ return 0 if @last_hit_at.nil?
19
+ entries_to_go_back = @hits.size - (now - @last_hit_at) - 2
20
+ return 0 if entries_to_go_back <= 0
21
+ sum = 0
22
+ entries_to_go_back.times do |i|
23
+ now -= 1
24
+ if @hits[now % @hits.size] && @hits[now % @hits.size][0] == now
25
+ sum += @hits[now % @hits.size][1]
26
+ end
27
+ end
28
+ return sum.to_f / (@hits.size - 2)
29
+ end
30
+ end
31
+ end
@@ -33,8 +33,9 @@ module Pandemic
33
33
  @clients_mutex = Mutex.new
34
34
  @num_jobs_processed = MutexCounter.new
35
35
  @num_jobs_entered = MutexCounter.new
36
+ @requests_per_second = RequestsPerSecond.new(10)
36
37
 
37
- @peers = {}
38
+ @peers = with_mutex({})
38
39
  @servers = Config.servers
39
40
  @servers.each do |peer|
40
41
  next if peer == bind_to # not a peer, it's itself
@@ -64,7 +65,7 @@ module Pandemic
64
65
  debug("Listening")
65
66
  conn = @listener.accept
66
67
  Thread.new(conn) { |c| handle_connection(c) }
67
- rescue Errno::ECONNABORTED, Errno::EINTR
68
+ rescue Errno::ECONNABORTED, Errno::EINTR # TODO: what else can wrong here? this should be more robust.
68
69
  debug("Connection accepted aborted")
69
70
  conn.close if conn && !conn.closed?
70
71
  end
@@ -96,8 +97,17 @@ module Pandemic
96
97
  debug("Recognized as peer")
97
98
  host, port = host_port($1)
98
99
  matching_peer = @peers.values.detect { |peer| [peer.host, peer.port] == [host, port] }
99
- debug("Found matching peer")
100
- matching_peer.add_incoming_connection(connection) unless matching_peer.nil?
100
+ if matching_peer
101
+ debug("Found matching peer")
102
+ else
103
+ debug("Didn't find matching peer, adding it")
104
+ matching_peer = @peers.synchronize do
105
+ hostport = "#{host}:#{port}"
106
+ @servers.push(hostport) unless @servers.include?(hostport)
107
+ @peers[hostport] ||= Peer.new(hostport, self)
108
+ end
109
+ end
110
+ matching_peer.add_incoming_connection(connection)
101
111
  elsif identification =~ /^CLIENT$/
102
112
  debug("Recognized as client")
103
113
  @clients_mutex.synchronize do
@@ -139,6 +149,8 @@ module Pandemic
139
149
  end
140
150
  end
141
151
 
152
+ @requests_per_second.hit
153
+
142
154
  debug("Waiting for responses")
143
155
  request.wait_for_responses
144
156
 
@@ -202,6 +214,8 @@ module Pandemic
202
214
  str << "Late Responses: #{stats[:late_responses]}"
203
215
  str << "Total Jobs Processed: #{stats[:total_jobs_processed]}"
204
216
  str << "Pending Jobs: #{stats[:jobs_pending]}"
217
+ str << "Requests per Second (10 sec): #{"%.1f" % stats[:rps_10]}"
218
+ str << "Requests per Second (lifetime): #{"%.1f" % stats[:rps_lifetime]}"
205
219
  connection.puts(str.join("\n"))
206
220
  end while (s = connection.gets) && (s.strip == "stats" || s.strip == "")
207
221
  connection.close if connection && !connection.closed?
@@ -243,8 +257,11 @@ module Pandemic
243
257
  pending + (client.received_requests - client.responded_requests.to_i)
244
258
  end
245
259
  end
260
+ results[:rps_10] = @requests_per_second.rps
246
261
 
247
262
  results[:uptime] = Time.now - @running_since
263
+ results[:rps_lifetime] = results[:num_requests] / results[:uptime]
264
+
248
265
  results
249
266
  end
250
267
 
data/pandemic.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{pandemic}
5
- s.version = "0.4.1"
5
+ s.version = "0.4.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Arya Asemanfar"]
9
- s.date = %q{2009-07-12}
9
+ s.date = %q{2009-07-20}
10
10
  s.description = %q{A framework for distributing work for real-time services and offline tasks.}
11
11
  s.email = %q{aryaasemanfar@gmail.com}
12
- s.extra_rdoc_files = ["lib/pandemic/client_side/cluster_connection.rb", "lib/pandemic/client_side/config.rb", "lib/pandemic/client_side/connection.rb", "lib/pandemic/client_side/connection_proxy.rb", "lib/pandemic/client_side/pandemize.rb", "lib/pandemic/connection_pool.rb", "lib/pandemic/mutex_counter.rb", "lib/pandemic/server_side/client.rb", "lib/pandemic/server_side/config.rb", "lib/pandemic/server_side/handler.rb", "lib/pandemic/server_side/peer.rb", "lib/pandemic/server_side/processor.rb", "lib/pandemic/server_side/request.rb", "lib/pandemic/server_side/server.rb", "lib/pandemic/util.rb", "lib/pandemic.rb", "README.markdown"]
13
- s.files = ["examples/client/client.rb", "examples/client/constitution.txt", "examples/client/pandemic_client.yml", "examples/server/pandemic_server.yml", "examples/server/word_count_server.rb", "lib/pandemic/client_side/cluster_connection.rb", "lib/pandemic/client_side/config.rb", "lib/pandemic/client_side/connection.rb", "lib/pandemic/client_side/connection_proxy.rb", "lib/pandemic/client_side/pandemize.rb", "lib/pandemic/connection_pool.rb", "lib/pandemic/mutex_counter.rb", "lib/pandemic/server_side/client.rb", "lib/pandemic/server_side/config.rb", "lib/pandemic/server_side/handler.rb", "lib/pandemic/server_side/peer.rb", "lib/pandemic/server_side/processor.rb", "lib/pandemic/server_side/request.rb", "lib/pandemic/server_side/server.rb", "lib/pandemic/util.rb", "lib/pandemic.rb", "Manifest", "MIT-LICENSE", "pandemic.gemspec", "Rakefile", "README.markdown", "test/client_test.rb", "test/connection_pool_test.rb", "test/functional_test.rb", "test/handler_test.rb", "test/mutex_counter_test.rb", "test/peer_test.rb", "test/processor_test.rb", "test/server_test.rb", "test/test_helper.rb", "test/util_test.rb"]
12
+ s.extra_rdoc_files = ["lib/pandemic/client_side/cluster_connection.rb", "lib/pandemic/client_side/config.rb", "lib/pandemic/client_side/connection.rb", "lib/pandemic/client_side/connection_proxy.rb", "lib/pandemic/client_side/pandemize.rb", "lib/pandemic/connection_pool.rb", "lib/pandemic/mutex_counter.rb", "lib/pandemic/requests_per_second.rb", "lib/pandemic/server_side/client.rb", "lib/pandemic/server_side/config.rb", "lib/pandemic/server_side/handler.rb", "lib/pandemic/server_side/peer.rb", "lib/pandemic/server_side/processor.rb", "lib/pandemic/server_side/request.rb", "lib/pandemic/server_side/server.rb", "lib/pandemic/util.rb", "lib/pandemic.rb", "README.markdown"]
13
+ s.files = ["examples/client/client.rb", "examples/client/constitution.txt", "examples/client/pandemic_client.yml", "examples/server/pandemic_server.yml", "examples/server/word_count_server.rb", "lib/pandemic/client_side/cluster_connection.rb", "lib/pandemic/client_side/config.rb", "lib/pandemic/client_side/connection.rb", "lib/pandemic/client_side/connection_proxy.rb", "lib/pandemic/client_side/pandemize.rb", "lib/pandemic/connection_pool.rb", "lib/pandemic/mutex_counter.rb", "lib/pandemic/requests_per_second.rb", "lib/pandemic/server_side/client.rb", "lib/pandemic/server_side/config.rb", "lib/pandemic/server_side/handler.rb", "lib/pandemic/server_side/peer.rb", "lib/pandemic/server_side/processor.rb", "lib/pandemic/server_side/request.rb", "lib/pandemic/server_side/server.rb", "lib/pandemic/util.rb", "lib/pandemic.rb", "Manifest", "MIT-LICENSE", "pandemic.gemspec", "Rakefile", "README.markdown", "test/client_test.rb", "test/connection_pool_test.rb", "test/functional_test.rb", "test/handler_test.rb", "test/mutex_counter_test.rb", "test/peer_test.rb", "test/processor_test.rb", "test/server_test.rb", "test/test_helper.rb", "test/util_test.rb"]
14
14
  s.homepage = %q{https://github.com/arya/pandemic/}
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Pandemic", "--main", "README.markdown"]
16
16
  s.require_paths = ["lib"]
data/test/server_test.rb CHANGED
@@ -3,6 +3,33 @@ require 'test_helper'
3
3
  class ServerTest < Test::Unit::TestCase
4
4
  include TestHelper
5
5
 
6
+ context "without a peer list" do
7
+ setup do
8
+ Pandemic::ServerSide::Config.expects(:servers).returns(["localhost:4000"])
9
+ @server = Pandemic::ServerSide::Server.new("localhost:4000")
10
+ end
11
+
12
+ should "create a peer connection when a unknown peer tries to connect" do
13
+ ignore_threads = Thread.list
14
+ @tcpserver = mock()
15
+ TCPServer.expects(:new).with("localhost", 4000).returns(@tcpserver)
16
+
17
+ @conn = mock(:peeraddr => ['','','',''])
18
+ @tcpserver.expects(:accept).twice.returns(@conn).then.raises(Pandemic::ServerSide::Server::StopServer)
19
+ peer = mock()
20
+ @conn.expects(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
21
+
22
+ @conn.expects(:gets).returns("SERVER localhost:4001\n")
23
+ Pandemic::ServerSide::Peer.expects(:new).with("localhost:4001", is_a(Pandemic::ServerSide::Server)).returns(peer)
24
+ @tcpserver.expects(:close)
25
+ peer.stubs(:disconnect) # the StopServer signal could be called before the peer is added. race case not important for this test
26
+
27
+ @server.handler = mock(:new)
28
+ @server.start
29
+ wait_for_threads(ignore_threads)
30
+ end
31
+ end
32
+
6
33
  should "initialize peers" do
7
34
  Pandemic::ServerSide::Config.expects(:servers).returns(["localhost:4000", "localhost:4001"])
8
35
  Pandemic::ServerSide::Peer.expects(:new).with("localhost:4001", is_a(Pandemic::ServerSide::Server))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arya-pandemic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arya Asemanfar
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-12 00:00:00 -07:00
12
+ date: 2009-07-20 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -46,6 +46,7 @@ extra_rdoc_files:
46
46
  - lib/pandemic/client_side/pandemize.rb
47
47
  - lib/pandemic/connection_pool.rb
48
48
  - lib/pandemic/mutex_counter.rb
49
+ - lib/pandemic/requests_per_second.rb
49
50
  - lib/pandemic/server_side/client.rb
50
51
  - lib/pandemic/server_side/config.rb
51
52
  - lib/pandemic/server_side/handler.rb
@@ -69,6 +70,7 @@ files:
69
70
  - lib/pandemic/client_side/pandemize.rb
70
71
  - lib/pandemic/connection_pool.rb
71
72
  - lib/pandemic/mutex_counter.rb
73
+ - lib/pandemic/requests_per_second.rb
72
74
  - lib/pandemic/server_side/client.rb
73
75
  - lib/pandemic/server_side/config.rb
74
76
  - lib/pandemic/server_side/handler.rb