sanford 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -144,14 +144,16 @@ Define a `name` on a Host to set a string name for your host that can be used to
144
144
 
145
145
  ### Loading An Application
146
146
 
147
- Typically, a Sanford host is part of a larger application and parts of the application need to be setup or loaded when you start your Sanford server. The task `sanford:setup` is called before running any start, stop, or restart task; override it to hook in your application setup code:
147
+ Typically, a Sanford host is part of a larger application and parts of the application need to be setup or loaded when you start your Sanford server. to support this, Sanford provides a `setup` hook for hosts. The proc that is defined will be called before the Sanford server is started, properly running the server in your application's environment:
148
148
 
149
149
  ```ruby
150
- # In your Rakefile
151
- namespace :sanford do
152
- task :setup do
153
- require 'config/environment'
150
+ class MyHost
151
+ include Sanford::Host
152
+
153
+ setup do
154
+ require File.expand_path("../config/environment", __FILE__)
154
155
  end
156
+
155
157
  end
156
158
  ```
157
159
 
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
- ENV['SANFORD_SERVICES_CONFIG'] = 'bench/services'
3
+ ENV['SANFORD_SERVICES_FILE'] = 'bench/services'
4
4
  require 'sanford/rake'
5
5
  require 'bench/tasks'
6
6
 
data/bench/report.txt CHANGED
@@ -2,39 +2,39 @@ Running benchmark report...
2
2
 
3
3
  Hitting "simple" service with {}, 10000 times
4
4
  ....................................................................................................
5
- Total Time: 10195.4432ms
6
- Average Time: 1.0195ms
7
- Min Time: 0.7040ms
8
- Max Time: 117.8309ms
5
+ Total Time: 10515.3759ms
6
+ Average Time: 1.0515ms
7
+ Min Time: 0.7140ms
8
+ Max Time: 114.8610ms
9
9
 
10
10
  Distribution (number of requests):
11
- 0ms: 8897
12
- 0.7ms: 6897
13
- 0.8ms: 1451
14
- 0.9ms: 549
15
- 1ms: 1049
16
- 1.0ms: 308
17
- 1.1ms: 236
18
- 1.2ms: 198
19
- 1.3ms: 134
20
- 1.4ms: 66
21
- 1.5ms: 44
22
- 1.6ms: 26
23
- 1.7ms: 18
24
- 1.8ms: 15
11
+ 0ms: 8614
12
+ 0.7ms: 4945
13
+ 0.8ms: 2641
14
+ 0.9ms: 1028
15
+ 1ms: 1339
16
+ 1.0ms: 612
17
+ 1.1ms: 370
18
+ 1.2ms: 172
19
+ 1.3ms: 90
20
+ 1.4ms: 39
21
+ 1.5ms: 19
22
+ 1.6ms: 16
23
+ 1.7ms: 10
24
+ 1.8ms: 7
25
25
  1.9ms: 4
26
- 117ms: 1
27
- 2ms: 24
28
- 3ms: 7
29
- 4ms: 2
30
- 82ms: 1
31
- 83ms: 1
32
- 84ms: 3
33
- 85ms: 2
34
- 86ms: 2
35
- 88ms: 3
36
- 89ms: 4
37
- 90ms: 2
26
+ 2ms: 15
27
+ 3ms: 10
28
+ 4ms: 1
29
+ 66ms: 1
30
+ 86ms: 3
31
+ 87ms: 4
32
+ 89ms: 2
33
+ 90ms: 3
38
34
  91ms: 2
35
+ 92ms: 2
36
+ 93ms: 1
37
+ 94ms: 2
38
+ 114ms: 1
39
39
 
40
40
  Done running benchmark report
@@ -7,8 +7,9 @@ module Sanford
7
7
 
8
8
  attr_reader :exception, :host_data, :request
9
9
 
10
- def initialize(exception, host_data, request = nil)
10
+ def initialize(exception, host_data = nil, request = nil)
11
11
  @exception, @host_data, @request = exception, host_data, request
12
+ @error_proc = @host_data ? @host_data.error_proc : proc{ }
12
13
  end
13
14
 
14
15
  # The exception that we are generating a response for can change in the case
@@ -19,7 +20,7 @@ module Sanford
19
20
 
20
21
  def run
21
22
  begin
22
- result = @host_data.error_proc.call(@exception, @host_data, @request)
23
+ result = @error_proc.call(@exception, @host_data, @request)
23
24
  rescue Exception => proc_exception
24
25
  @exception = proc_exception
25
26
  end
@@ -5,7 +5,6 @@ module Sanford
5
5
  NotFoundError = Class.new(RuntimeError)
6
6
 
7
7
  class NoHostError < BaseError
8
- attr_reader :message
9
8
 
10
9
  def initialize(host_name)
11
10
  message = if Sanford.hosts.empty?
data/lib/sanford/host.rb CHANGED
@@ -25,6 +25,7 @@ module Sanford
25
25
  option :logger, :default => proc{ Sanford::NullLogger.new }
26
26
  option :verbose_logging, :default => true
27
27
  option :error_proc, Proc, :default => proc{ }
28
+ option :setup_proc, Proc, :default => proc{ }
28
29
 
29
30
  def initialize(host)
30
31
  self.name = host.class.to_s
@@ -75,6 +76,10 @@ module Sanford
75
76
  self.configuration.error_proc = block
76
77
  end
77
78
 
79
+ def setup(&block)
80
+ self.configuration.setup_proc = block
81
+ end
82
+
78
83
  def version(name, &block)
79
84
  version_group = Sanford::Host::VersionGroup.new(name, &block)
80
85
  @versioned_services.merge!(version_group.to_hash)
@@ -20,14 +20,21 @@ module Sanford
20
20
  @pid_dir = configuration[:pid_dir]
21
21
  @logger, @verbose = configuration[:logger], configuration[:verbose_logging]
22
22
  @error_proc = configuration[:error_proc]
23
+ @setup_proc = configuration[:setup_proc]
23
24
 
24
- @handlers = service_host.versioned_services.inject({}) do |hash, (version, services)|
25
- hash.merge({ version => self.constantize_services(services) })
26
- end
25
+ @versioned_services = service_host.versioned_services
26
+ @handlers = {}
27
27
 
28
28
  raise Sanford::InvalidHostError.new(service_host) if !self.port
29
29
  end
30
30
 
31
+ def setup
32
+ @setup_proc.call
33
+ @handlers = @versioned_services.inject({}) do |hash, (version, services)|
34
+ hash.merge({ version => self.constantize_services(services) })
35
+ end
36
+ end
37
+
31
38
  def handler_class_for(version, service)
32
39
  version_group = @handlers[version] || {}
33
40
  version_group[service] || raise(Sanford::NotFoundError)
@@ -19,18 +19,18 @@ module Sanford
19
19
  self.new(service_host, options).call(action)
20
20
  end
21
21
 
22
- attr_reader :host, :process_name
22
+ attr_reader :host_data, :process_name
23
23
 
24
24
  def initialize(service_host, options = {})
25
- @host = Sanford::HostData.new(service_host, options)
26
- @process_name = [ self.host.ip, self.host.port, self.host.name ].join('_')
25
+ @host_data = Sanford::HostData.new(service_host, options)
26
+ @process_name = [ self.host_data.ip, self.host_data.port, self.host_data.name ].join('_')
27
27
  end
28
28
 
29
29
  def call(action)
30
30
  daemons_options = self.default_options.merge({ :ARGV => [ action.to_s ] })
31
31
  FileUtils.mkdir_p(daemons_options[:dir])
32
32
  ::Daemons.run_proc(self.process_name, daemons_options) do
33
- server = Sanford::Server.new(self.host)
33
+ server = Sanford::Server.new(self.host_data)
34
34
  server.start
35
35
  server.join_thread
36
36
  end
@@ -40,7 +40,7 @@ module Sanford
40
40
 
41
41
  def default_options
42
42
  { :dir_mode => :normal,
43
- :dir => self.host.pid_dir
43
+ :dir => self.host_data.pid_dir
44
44
  }
45
45
  end
46
46
 
data/lib/sanford/rake.rb CHANGED
@@ -6,11 +6,7 @@ module Sanford::Rake
6
6
  def self.load
7
7
  namespace :sanford do
8
8
 
9
- # Overwrite this to load your application's environment so that it can
10
- # be used with Sanford
11
- task :setup
12
-
13
- task :load_manager => :setup do
9
+ task :load_manager do
14
10
  require 'sanford'
15
11
  require 'sanford/manager'
16
12
  Sanford.init
@@ -13,6 +13,7 @@ module Sanford
13
13
 
14
14
  def initialize(host, options = {})
15
15
  @host_data = host.kind_of?(Sanford::HostData) ? host : Sanford::HostData.new(host)
16
+ @host_data.setup
16
17
  super(@host_data.ip, @host_data.port, options)
17
18
  end
18
19
 
@@ -1,3 +1,3 @@
1
1
  module Sanford
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -34,21 +34,42 @@ module Sanford
34
34
  protected
35
35
 
36
36
  def run!
37
- request, handler_class, response, exception = nil, nil, nil, nil
37
+ service = ProcessedService.new
38
38
  begin
39
39
  request = Sanford::Protocol::Request.parse(@connection.read_data)
40
40
  self.log_request(request)
41
+ service.request = request
42
+
41
43
  handler_class = @host_data.handler_class_for(request.version, request.name)
42
44
  self.log_handler_class(handler_class)
45
+ service.handler_class = handler_class
46
+
43
47
  response = Sanford::Runner.new(handler_class, request, @host_data.logger).run
48
+ service.response = response
44
49
  rescue Exception => exception
45
- error_handler = Sanford::ErrorHandler.new(exception, @host_data, request)
46
- response = error_handler.run
47
- self.log_exception(error_handler.exception)
50
+ self.handle_exception(service, exception, @host_data)
48
51
  ensure
49
- @connection.write_data response.to_hash
52
+ self.write_response(service)
50
53
  end
51
- ProcessedService.new(request, handler_class, response, exception)
54
+ service
55
+ end
56
+
57
+ def write_response(service)
58
+ begin
59
+ @connection.write_data service.response.to_hash
60
+ rescue Exception => exception
61
+ service = self.handle_exception(service, exception)
62
+ @connection.write_data service.response.to_hash
63
+ end
64
+ service
65
+ end
66
+
67
+ def handle_exception(service, exception, host_data = nil)
68
+ error_handler = Sanford::ErrorHandler.new(exception, host_data, service.request)
69
+ service.response = error_handler.run
70
+ service.exception = error_handler.exception
71
+ self.log_exception(service.exception)
72
+ service
52
73
  end
53
74
 
54
75
  def raise_if_debugging!(exception)
@@ -2,16 +2,21 @@ class FakeConnection
2
2
 
3
3
  attr_reader :read_data, :response
4
4
 
5
- def self.with_request(version, name, params = {})
5
+ def self.with_request(version, name, params = {}, raise_on_write = false)
6
6
  request = Sanford::Protocol::Request.new(version, name, params)
7
- self.new(request.to_hash)
7
+ self.new(request.to_hash, raise_on_write)
8
8
  end
9
9
 
10
- def initialize(read_data)
10
+ def initialize(read_data, raise_on_write = false)
11
+ @raise_on_write = raise_on_write
11
12
  @read_data = read_data
12
13
  end
13
14
 
14
15
  def write_data(data)
16
+ if @raise_on_write
17
+ @raise_on_write = false
18
+ raise 'test fail'
19
+ end
15
20
  @response = Sanford::Protocol::Response.parse(data)
16
21
  end
17
22
 
@@ -3,6 +3,12 @@ require 'logger'
3
3
  class TestHost
4
4
  include Sanford::Host
5
5
 
6
+ attr_accessor :setup_has_been_called
7
+
8
+ setup do
9
+ self.setup_has_been_called = true
10
+ end
11
+
6
12
  ip 'localhost'
7
13
  port 12000
8
14
  pid_dir File.expand_path('../../../tmp/', __FILE__)
@@ -107,6 +113,8 @@ end
107
113
  class UndefinedHandlersHost
108
114
  include Sanford::Host
109
115
 
116
+ port 12345
117
+
110
118
  version 'v1' do
111
119
  service 'undefined', 'ThisIsNotDefined'
112
120
  end
@@ -12,7 +12,7 @@ class Sanford::HostData
12
12
  subject{ @host_data }
13
13
 
14
14
  should have_instance_methods :name, :ip, :port, :pid_dir, :logger, :verbose,
15
- :error_proc, :handler_class_for
15
+ :error_proc, :handler_class_for, :setup
16
16
 
17
17
  should "default it's configuration from the service host, but allow overrides" do
18
18
  host_data = Sanford::HostData.new(TestHost, :ip => '1.2.3.4', :port => 12345)
@@ -22,16 +22,6 @@ class Sanford::HostData
22
22
  assert_equal 12345, host_data.port
23
23
  end
24
24
 
25
- should "constantize a host's handlers" do
26
- handlers = subject.instance_variable_get("@handlers")
27
-
28
- assert_equal TestHost::Authorized, handlers['v1']['authorized']
29
- assert_equal TestHost::Bad, handlers['v1']['bad']
30
- assert_equal TestHost::Echo, handlers['v1']['echo']
31
- assert_equal TestHost::HaltIt, handlers['v1']['halt_it']
32
- assert_equal TestHost::Multiply, handlers['v1']['multiply']
33
- end
34
-
35
25
  should "ignore nil values passed as overrides" do
36
26
  host_data = Sanford::HostData.new(TestHost, :ip => nil)
37
27
 
@@ -44,7 +34,31 @@ class Sanford::HostData
44
34
  end
45
35
  end
46
36
 
47
- should "look up handler classes with #handler_class_for" do
37
+ end
38
+
39
+ class SetupTest < BaseTest
40
+ desc "after calling setup"
41
+ setup do
42
+ TestHost.setup_has_been_called = false
43
+ @host_data.setup
44
+ end
45
+
46
+ should "have called the setup proc" do
47
+ assert_equal true, TestHost.setup_has_been_called
48
+
49
+ TestHost.setup_has_been_called = false
50
+ end
51
+
52
+ should "constantize a host's handlers" do
53
+ handlers = subject.instance_variable_get("@handlers")
54
+ assert_equal TestHost::Authorized, handlers['v1']['authorized']
55
+ assert_equal TestHost::Bad, handlers['v1']['bad']
56
+ assert_equal TestHost::Echo, handlers['v1']['echo']
57
+ assert_equal TestHost::HaltIt, handlers['v1']['halt_it']
58
+ assert_equal TestHost::Multiply, handlers['v1']['multiply']
59
+ end
60
+
61
+ should "look up handler classes with #handler_class_for" do
48
62
  assert_equal TestHost::Echo, subject.handler_class_for('v1', 'echo')
49
63
  end
50
64
 
@@ -56,7 +70,7 @@ class Sanford::HostData
56
70
 
57
71
  should "raise a custom error when a service is configured with an undefined class" do
58
72
  assert_raises(Sanford::NoHandlerClassError) do
59
- Sanford::HostData.new(UndefinedHandlersHost)
73
+ Sanford::HostData.new(UndefinedHandlersHost).setup
60
74
  end
61
75
  end
62
76
 
@@ -13,15 +13,13 @@ module Sanford::Host
13
13
  subject{ MyHost.instance }
14
14
 
15
15
  should have_instance_methods :configuration, :name, :ip, :port, :pid_dir, :logger,
16
- :verbose_logging, :error, :version, :versioned_services
16
+ :verbose_logging, :error, :setup, :version, :versioned_services
17
17
 
18
18
  should "get and set it's configuration options with their matching methods" do
19
19
  subject.name 'my_awesome_host'
20
20
 
21
21
  assert_equal 'my_awesome_host', subject.name
22
22
  assert_equal subject.configuration.port, subject.port
23
-
24
-
25
23
  end
26
24
 
27
25
  should "add a version group with #version" do
@@ -11,7 +11,7 @@ class Sanford::Manager
11
11
  end
12
12
  subject{ @manager }
13
13
 
14
- should have_instance_methods :host, :process_name, :call
14
+ should have_instance_methods :host_data, :process_name, :call
15
15
  should have_class_methods :call
16
16
  end
17
17
 
@@ -24,7 +24,7 @@ class Sanford::Worker
24
24
 
25
25
  desc "Sanford::Worker"
26
26
  setup do
27
- @host_data = Sanford::HostData.new(TestHost)
27
+ @host_data = Sanford::HostData.new(TestHost).tap{|hd| hd.setup }
28
28
  @connection = FakeConnection.with_request('version', 'service', {})
29
29
  @worker = Sanford::Worker.new(@host_data, @connection)
30
30
  end
@@ -192,4 +192,22 @@ class Sanford::Worker
192
192
 
193
193
  end
194
194
 
195
+ class WithBadResponseHashTest < BaseTest
196
+ desc "running a request that builds an object that can't be encoded"
197
+ setup do
198
+ @connection = FakeConnection.with_request('v1', 'echo', { :message => 'cant encode' }, true)
199
+ @worker = Sanford::Worker.new(@host_data, @connection)
200
+ end
201
+
202
+ should "return the response that was halted" do
203
+ assert_raises(RuntimeError){ @worker.run }
204
+ response = @connection.response
205
+
206
+ assert_equal 500, response.status.code
207
+ assert_equal "An unexpected error occurred.", response.status.message
208
+ assert_equal nil, response.data
209
+ end
210
+
211
+ end
212
+
195
213
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sanford
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Collin Redding
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2013-01-24 00:00:00 Z
19
+ date: 2013-01-28 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  prerelease: false