thrift_server 0.1.1 → 1.0.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.
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