thrift_server 0.1.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +2 -0
  3. data/Makefile +27 -14
  4. data/README.md +142 -43
  5. data/circle.yml +14 -0
  6. data/echo_client.rb +22 -3
  7. data/echo_server.rb +23 -16
  8. data/echo_service.thrift +11 -0
  9. data/lib/thrift_server.rb +112 -36
  10. data/lib/thrift_server/instrumentation_middleware.rb +33 -0
  11. data/lib/thrift_server/log_subscriber.rb +60 -0
  12. data/lib/thrift_server/publisher.rb +25 -0
  13. data/lib/thrift_server/rpc_metrics_subscriber.rb +25 -0
  14. data/lib/thrift_server/server_metrics_subscriber.rb +32 -0
  15. data/lib/thrift_server/thread_pool_server.rb +115 -0
  16. data/lib/thrift_server/threaded_server.rb +87 -0
  17. data/lib/thrift_server/validation_middleware.rb +14 -0
  18. data/lib/thrift_server/version.rb +2 -2
  19. data/script/circleci/cache-image +10 -0
  20. data/test/log_subscriber_test.rb +86 -0
  21. data/test/processor_test.rb +189 -0
  22. data/test/rpc_metrics_subscriber_test.rb +44 -0
  23. data/test/server_metrics_subscriber_test.rb +51 -0
  24. data/test/support/log_yielder.rb +32 -0
  25. data/test/support/server_tests.rb +87 -0
  26. data/test/test_helper.rb +32 -23
  27. data/test/thread_pool_server_test.rb +101 -0
  28. data/test/threaded_server_test.rb +56 -0
  29. data/test/validation_middleware_test.rb +71 -0
  30. data/thrift_server.gemspec +2 -2
  31. metadata +34 -22
  32. data/lib/thrift_server/error_tracking_middleware.rb +0 -12
  33. data/lib/thrift_server/honeybadger_error_tracker.rb +0 -11
  34. data/lib/thrift_server/logging_middleware.rb +0 -13
  35. data/lib/thrift_server/metrics_middleware.rb +0 -16
  36. data/script/buildbox/ci +0 -5
  37. data/script/buildbox/step_failed +0 -5
  38. data/test/acceptance_test.rb +0 -225
  39. data/test/error_tracking_middleware_test.rb +0 -25
  40. data/test/honeybadger_error_tracking_test.rb +0 -12
  41. data/test/logging_middleware_test.rb +0 -42
  42. data/test/metrics_middleware_test.rb +0 -70
@@ -0,0 +1,101 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ThreadPoolSeverTest < MiniTest::Unit::TestCase
4
+ include ServerTests
5
+
6
+ attr_reader :service
7
+
8
+ def setup
9
+ @service = TestService
10
+ end
11
+
12
+ def build(*args, &block)
13
+ ThriftServer.send :thread_pool, *args, &block
14
+ end
15
+
16
+ def test_returns_thread_pool_server
17
+ server = build service, stub
18
+
19
+ assert_kind_of Thrift::ThreadPoolServer, server
20
+ end
21
+
22
+ def test_defaults_to_25_threads
23
+ server = build service, stub
24
+
25
+ assert_equal 25, server.threads
26
+ end
27
+
28
+ def test_accepts_threads_option
29
+ server = build(service, stub, {
30
+ threads: 8
31
+ })
32
+
33
+ assert_equal 8, server.threads
34
+ end
35
+
36
+ def test_attaches_its_own_log_subscriber
37
+ ThriftServer::ThreadPoolServer::LogSubscriber.expects(:new).with(:stdout).returns(:custom)
38
+
39
+ server = build(service, stub) do |server|
40
+ server.log :stdout
41
+ end
42
+
43
+ assert_includes server.publisher, :custom
44
+ end
45
+
46
+ def test_start_up_logging
47
+ logger = mock
48
+ subscriber = ThriftServer::ThreadPoolServer::LogSubscriber.new LogYielder.new(logger)
49
+
50
+ server = stub({
51
+ port: 9999,
52
+ threads: 30,
53
+ transport: 'StubTransport',
54
+ protocol: 'StubProtocol'
55
+ })
56
+
57
+ logger.expects(:info).with do |line|
58
+ line =~ /9999/
59
+ end
60
+
61
+ logger.expects(:info).with do |line|
62
+ line =~ /30/
63
+ end
64
+
65
+ logger.expects(:info).with do |line|
66
+ line =~ /StubTransport/
67
+ end
68
+
69
+ logger.expects(:info).with do |line|
70
+ line =~ /StubProtocol/
71
+ end
72
+
73
+ subscriber.server_start server
74
+ end
75
+
76
+ def test_attaches_own_metrics_subcriber
77
+ ThriftServer::ThreadPoolServer::MetricsSubscriber.expects(:new).with(:statsd).returns(:custom)
78
+
79
+ server = build(service, stub) do |server|
80
+ server.metrics :statsd
81
+ end
82
+
83
+ assert_includes server.publisher, :custom
84
+ end
85
+
86
+ def test_thread_pool_server_pool_change_with_positive_delta
87
+ statsd = mock
88
+ subscriber = ThriftServer::ThreadPoolServer::MetricsSubscriber.new statsd
89
+
90
+ statsd.expects(:gauge).with('server.pool.size', '+1')
91
+ subscriber.thread_pool_server_pool_change delta: 1
92
+ end
93
+
94
+ def test_thread_pool_server_pool_change_with_negative_delta
95
+ statsd = mock
96
+ subscriber = ThriftServer::ThreadPoolServer::MetricsSubscriber.new statsd
97
+
98
+ statsd.expects(:gauge).with('server.pool.size', '-1')
99
+ subscriber.thread_pool_server_pool_change delta: -1
100
+ end
101
+ end
@@ -0,0 +1,56 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ThreadedServerTest < MiniTest::Unit::TestCase
4
+ include ServerTests
5
+
6
+ attr_reader :service
7
+
8
+ def setup
9
+ @service = TestService
10
+ end
11
+
12
+ def build(*args, &block)
13
+ ThriftServer.send :threaded, *args, &block
14
+ end
15
+
16
+ def test_is_threaded_server
17
+ server = build service, stub
18
+
19
+ assert_kind_of Thrift::ThreadedServer, server
20
+ end
21
+
22
+ def test_attaches_its_own_log_subscriber
23
+ ThriftServer::ThreadedServer::LogSubscriber.expects(:new).with(:stdout).returns(:custom)
24
+
25
+ server = build(service, stub) do |server|
26
+ server.log :stdout
27
+ end
28
+
29
+ assert_includes server.publisher, :custom
30
+ end
31
+
32
+ def test_start_up_logging
33
+ logger = mock
34
+ subscriber = ThriftServer::ThreadedServer::LogSubscriber.new LogYielder.new(logger)
35
+
36
+ server = stub({
37
+ port: 9999,
38
+ transport: 'StubTransport',
39
+ protocol: 'StubProtocol'
40
+ })
41
+
42
+ logger.expects(:info).with do |line|
43
+ line =~ /9999/
44
+ end
45
+
46
+ logger.expects(:info).with do |line|
47
+ line =~ /StubTransport/
48
+ end
49
+
50
+ logger.expects(:info).with do |line|
51
+ line =~ /StubProtocol/
52
+ end
53
+
54
+ subscriber.server_start server
55
+ end
56
+ end
@@ -0,0 +1,71 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ValidationMiddlewareTest < MiniTest::Unit::TestCase
4
+ class StructResponse
5
+ include ::Thrift::Struct
6
+
7
+ attr_reader :id
8
+
9
+ def initialize(id)
10
+ @id = id
11
+ end
12
+
13
+ def ==(other)
14
+ id == other.id
15
+ end
16
+ end
17
+
18
+ class UnionResponse
19
+ include ::Thrift::Struct_Union
20
+
21
+ attr_reader :id
22
+
23
+ def initialize(id)
24
+ @id = id
25
+ end
26
+
27
+ def ==(other)
28
+ id == other.id
29
+ end
30
+ end
31
+
32
+ attr_reader :rpc, :validator
33
+
34
+ def setup
35
+ @rpc = ThriftServer::RPC.new :foo, :bar
36
+ @validator = mock
37
+ end
38
+
39
+ def test_validates_struct_responses
40
+ response = StructResponse.new :struct
41
+ Thrift::Validator.expects(:new).returns validator
42
+ validator.expects(:validate).with(response)
43
+
44
+ app = stub call: response
45
+
46
+ middleware = ThriftServer::ValidationMiddleware.new app
47
+
48
+ assert_equal response, middleware.call(rpc)
49
+ end
50
+
51
+ def test_validates_union_responses
52
+ response = UnionResponse.new :union
53
+ Thrift::Validator.expects(:new).returns validator
54
+ validator.expects(:validate).with(response)
55
+
56
+ app = stub call: response
57
+
58
+ middleware = ThriftServer::ValidationMiddleware.new app
59
+
60
+ assert_equal response, middleware.call(rpc)
61
+ end
62
+
63
+ def test_passes_on_non_structs
64
+ app = stub call: :response
65
+ validator.expects(:validate).never
66
+
67
+ middleware = ThriftServer::ValidationMiddleware.new app
68
+
69
+ assert_equal :response, middleware.call(rpc)
70
+ end
71
+ end
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.name = "thrift_server"
8
8
  spec.version = ThriftServer::VERSION
9
9
  spec.authors = ["ahawkins"]
10
- spec.email = ["adam@saltside.se"]
10
+ spec.email = ["hi@ahawkins.me"]
11
11
  spec.summary = %q{Encapsulate error handling, logging, and metrics for thrift servers}
12
12
  spec.description = %q{}
13
13
  spec.homepage = "https://github.com/saltside/thrift_server-ruby"
@@ -21,8 +21,8 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency "statsd-ruby"
22
22
  spec.add_dependency "middleware"
23
23
  spec.add_dependency "concord"
24
- spec.add_dependency "honeybadger"
25
24
  spec.add_dependency "thrift"
25
+ spec.add_dependency "thrift-validator"
26
26
 
27
27
  spec.add_development_dependency "bundler", "~> 1.6"
28
28
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thrift_server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ahawkins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-08 00:00:00.000000000 Z
11
+ date: 2017-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: statsd-ruby
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: honeybadger
56
+ name: thrift
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: thrift
70
+ name: thrift-validator
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -152,7 +152,7 @@ dependencies:
152
152
  version: '0'
153
153
  description: ''
154
154
  email:
155
- - adam@saltside.se
155
+ - hi@ahawkins.me
156
156
  executables: []
157
157
  extensions: []
158
158
  extra_rdoc_files: []
@@ -167,23 +167,31 @@ files:
167
167
  - Rakefile
168
168
  - Vagrantfile
169
169
  - benchmark/server.rb
170
+ - circle.yml
170
171
  - echo_client.rb
171
172
  - echo_server.rb
172
173
  - echo_service.thrift
173
174
  - lib/thrift_server.rb
174
- - lib/thrift_server/error_tracking_middleware.rb
175
- - lib/thrift_server/honeybadger_error_tracker.rb
176
- - lib/thrift_server/logging_middleware.rb
177
- - lib/thrift_server/metrics_middleware.rb
175
+ - lib/thrift_server/instrumentation_middleware.rb
176
+ - lib/thrift_server/log_subscriber.rb
177
+ - lib/thrift_server/publisher.rb
178
+ - lib/thrift_server/rpc_metrics_subscriber.rb
179
+ - lib/thrift_server/server_metrics_subscriber.rb
180
+ - lib/thrift_server/thread_pool_server.rb
181
+ - lib/thrift_server/threaded_server.rb
182
+ - lib/thrift_server/validation_middleware.rb
178
183
  - lib/thrift_server/version.rb
179
- - script/buildbox/ci
180
- - script/buildbox/step_failed
181
- - test/acceptance_test.rb
182
- - test/error_tracking_middleware_test.rb
183
- - test/honeybadger_error_tracking_test.rb
184
- - test/logging_middleware_test.rb
185
- - test/metrics_middleware_test.rb
184
+ - script/circleci/cache-image
185
+ - test/log_subscriber_test.rb
186
+ - test/processor_test.rb
187
+ - test/rpc_metrics_subscriber_test.rb
188
+ - test/server_metrics_subscriber_test.rb
189
+ - test/support/log_yielder.rb
190
+ - test/support/server_tests.rb
186
191
  - test/test_helper.rb
192
+ - test/thread_pool_server_test.rb
193
+ - test/threaded_server_test.rb
194
+ - test/validation_middleware_test.rb
187
195
  - thrift_server.gemspec
188
196
  homepage: https://github.com/saltside/thrift_server-ruby
189
197
  licenses:
@@ -205,14 +213,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
213
  version: '0'
206
214
  requirements: []
207
215
  rubyforge_project:
208
- rubygems_version: 2.2.2
216
+ rubygems_version: 2.5.1
209
217
  signing_key:
210
218
  specification_version: 4
211
219
  summary: Encapsulate error handling, logging, and metrics for thrift servers
212
220
  test_files:
213
- - test/acceptance_test.rb
214
- - test/error_tracking_middleware_test.rb
215
- - test/honeybadger_error_tracking_test.rb
216
- - test/logging_middleware_test.rb
217
- - test/metrics_middleware_test.rb
221
+ - test/log_subscriber_test.rb
222
+ - test/processor_test.rb
223
+ - test/rpc_metrics_subscriber_test.rb
224
+ - test/server_metrics_subscriber_test.rb
225
+ - test/support/log_yielder.rb
226
+ - test/support/server_tests.rb
218
227
  - test/test_helper.rb
228
+ - test/thread_pool_server_test.rb
229
+ - test/threaded_server_test.rb
230
+ - test/validation_middleware_test.rb
@@ -1,12 +0,0 @@
1
- class ThriftServer
2
- class ErrorTrackingMiddleware
3
- include Concord.new(:app, :logger)
4
-
5
- def call(rpc)
6
- app.call rpc
7
- rescue => ex
8
- logger.track rpc, ex
9
- raise ex
10
- end
11
- end
12
- end
@@ -1,11 +0,0 @@
1
- class ThriftServer
2
- class HoneybadgerErrorTracker
3
- def initialize(client = Honeybadger)
4
- @client = client
5
- end
6
-
7
- def track(rpc, error)
8
- @client.notify_or_ignore error
9
- end
10
- end
11
- end
@@ -1,13 +0,0 @@
1
- class ThriftServer
2
- class LoggingMiddleware
3
- include Concord.new(:app, :logger)
4
-
5
- def call(rpc)
6
- logger.info "Incoming RPC: #{rpc.name}"
7
- app.call rpc
8
- rescue => ex
9
- logger.error ex
10
- raise ex
11
- end
12
- end
13
- end
@@ -1,16 +0,0 @@
1
- class ThriftServer
2
- class MetricsMiddleware
3
- include Concord.new(:app, :statsd)
4
-
5
- def call(rpc)
6
- statsd.increment rpc.name
7
-
8
- statsd.time rpc.name do
9
- app.call rpc
10
- end
11
- rescue => ex
12
- statsd.increment 'errors'
13
- raise ex
14
- end
15
- end
16
- end
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- set -eou pipefail
4
-
5
- make test-ci clean
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- set -eou pipefail
4
-
5
- make clean
@@ -1,225 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class AcceptanceTest < MiniTest::Unit::TestCase
4
- attr_reader :processor
5
-
6
- def setup
7
- @processor = Processor(:getItems)
8
- end
9
-
10
- def wrap(klass, &block)
11
- ThriftServer.wrap(processor, {
12
- logger: NullLogger.new,
13
- statsd: FakeStatsd.new,
14
- error_tracker: NullErrorTracker.new,
15
- }, &block)
16
- end
17
-
18
- def test_wrap_fails_if_no_logger
19
- ex = assert_raises ArgumentError do
20
- ThriftServer.wrap(processor, {
21
- statsd: FakeStatsd.new,
22
- error_tracker: NullErrorTracker.new,
23
- })
24
- end
25
-
26
- assert_match /logger/, ex.to_s
27
- end
28
-
29
- def test_wrap_fails_if_no_stats
30
- ex = assert_raises ArgumentError do
31
- ThriftServer.wrap(processor, {
32
- logger: NullLogger.new,
33
- error_tracker: NullErrorTracker.new,
34
- })
35
- end
36
-
37
- assert_match /statsd/, ex.to_s
38
- end
39
-
40
- def test_wrap_fails_if_no_error_tracker
41
- ex = assert_raises ArgumentError do
42
- ThriftServer.wrap(processor, {
43
- logger: NullLogger.new,
44
- statsd: FakeStatsd.new
45
- })
46
- end
47
-
48
- assert_match /error_tracker/, ex.to_s
49
- end
50
-
51
- def test_wraps_methods_defined_by_the_protocol
52
- handler = stub
53
- handler.expects(:getItems).with(:request).returns(:response)
54
-
55
- stack = wrap(processor).new(handler)
56
-
57
- assert_equal :response, stack.process_getItems(:request)
58
- end
59
-
60
- def test_can_add_new_middleware_after_wrapping
61
- handler = mock
62
- handler.expects(:getItems).with(:modified_args)
63
-
64
- stack = wrap(processor).new(handler)
65
-
66
- test_middleware = Class.new do
67
- def initialize(app)
68
- @app = app
69
- end
70
-
71
- def call(env)
72
- env.args = :modified_args
73
- @app.call env
74
- end
75
- end
76
-
77
- stack.use test_middleware
78
-
79
- stack.process_getItems :request
80
- end
81
-
82
- def test_cannot_add_middleware_to_stack_after_first_rpc
83
- handler = stub getItems: :response
84
-
85
- stack = wrap(processor).new(handler)
86
-
87
- stack.process_getItems :request
88
-
89
- ex = assert_raises RuntimeError do
90
- stack.use ->(rpc) { rpc }
91
- end
92
-
93
- assert_match /frozen/, ex.to_s
94
- end
95
-
96
- def test_wrap_yields_the_middleware_stack
97
- handler = mock
98
- handler.expects(:getItems).with(:from_block)
99
-
100
- test_middleware = Class.new do
101
- def initialize(app)
102
- @app = app
103
- end
104
-
105
- def call(env)
106
- env.args = :from_block
107
- @app.call env
108
- end
109
- end
110
-
111
- stack_processor = wrap processor do |stack|
112
- stack.use test_middleware
113
- end
114
- stack = stack_processor.new(handler)
115
-
116
- stack.process_getItems :request
117
- end
118
-
119
- def test_build_returns_thread_pool_server
120
- handler = stub getItems: :response
121
- server = ThriftServer.build(processor, handler, {
122
- logger: NullLogger.new,
123
- statsd: FakeStatsd.new,
124
- error_tracker: NullErrorTracker.new
125
- })
126
-
127
- assert_instance_of Thrift::ThreadPoolServer, server
128
- end
129
-
130
- def test_build_defaults_to_port_9090
131
- handler = stub getItems: :response
132
- server = ThriftServer.build(processor, handler, {
133
- logger: NullLogger.new,
134
- statsd: FakeStatsd.new,
135
- error_tracker: NullErrorTracker.new
136
- })
137
-
138
- assert_equal 9090, server.port
139
- end
140
-
141
- def test_build_accepts_port_options
142
- handler = stub getItems: :response
143
- server = ThriftServer.build(processor, handler, {
144
- logger: NullLogger.new,
145
- statsd: FakeStatsd.new,
146
- error_tracker: NullErrorTracker.new,
147
- port: 5000
148
- })
149
-
150
- assert_equal 5000, server.port
151
- end
152
-
153
- def test_build_defaults_to_4_threads
154
- handler = stub getItems: :response
155
- server = ThriftServer.build(processor, handler, {
156
- logger: NullLogger.new,
157
- statsd: FakeStatsd.new,
158
- error_tracker: NullErrorTracker.new
159
- })
160
-
161
- assert_equal 4, server.threads
162
- end
163
-
164
- def test_build_accepts_threads_option
165
- handler = stub getItems: :response
166
- server = ThriftServer.build(processor, handler, {
167
- logger: NullLogger.new,
168
- statsd: FakeStatsd.new,
169
- error_tracker: NullErrorTracker.new,
170
- threads: 8
171
- })
172
-
173
- assert_equal 8, server.threads
174
- end
175
-
176
- def test_builds_creates_server_with_framed_transport
177
- handler = stub getItems: :response
178
- server = ThriftServer.build(processor, handler, {
179
- logger: NullLogger.new,
180
- statsd: FakeStatsd.new,
181
- error_tracker: NullErrorTracker.new
182
- })
183
-
184
- assert_instance_of Thrift::FramedTransportFactory, server.transport_factory
185
- end
186
-
187
- def test_build_uses_server_socket_transport
188
- handler = stub getItems: :response
189
- server = ThriftServer.build(processor, handler, {
190
- logger: NullLogger.new,
191
- statsd: FakeStatsd.new,
192
- error_tracker: NullErrorTracker.new
193
- })
194
-
195
- assert_instance_of Thrift::ServerSocket, server.server_transport
196
- end
197
-
198
- def test_build_creates_server_with_binary_protocol
199
- handler = stub getItems: :response
200
- server = ThriftServer.build(processor, handler, {
201
- logger: NullLogger.new,
202
- statsd: FakeStatsd.new,
203
- error_tracker: NullErrorTracker.new
204
- })
205
-
206
- assert_instance_of Thrift::BinaryProtocolFactory, server.protocol_factory
207
- end
208
-
209
- def test_buil_accepts_a_block_to_customize_the_middleware_stack
210
- handler = stub getItems: :response
211
- block_yielded = false
212
-
213
- server = ThriftServer.build(processor, handler, {
214
- logger: NullLogger.new,
215
- statsd: FakeStatsd.new,
216
- error_tracker: NullErrorTracker.new
217
- }) do |stack|
218
- block_yielded = true
219
-
220
- assert_instance_of ThriftServer::MiddlewareStack, stack
221
- end
222
-
223
- assert block_yielded, 'Block not used'
224
- end
225
- end