sanford 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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