thrift_rack 0.2.5 → 0.2.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91940d7237d325873fa1aa7b9a6db6d93549d76c60ce045695652664aa1ac375
4
- data.tar.gz: 3853a703f5aa6b3aae575d18963c16c2b366c6da43faa186ea8dd2893037b2c0
3
+ metadata.gz: 3f79e2c9d1ce63045d0fb7042f7109911a632fec51c7e09a9c8edde7958447b5
4
+ data.tar.gz: 6f421077a9a66de076519bcfe42beb9f0316e928b36402bad86dea39ba71afee
5
5
  SHA512:
6
- metadata.gz: 7271e71e2410c02aa94ef4e81b0e5be8e0f310dda5338cde11f7d4458c8ee7cf84197a895b8e2fd7cf1905b1d849ee02d90951bfc17cd939908f617b07e77221
7
- data.tar.gz: fa40c932b3bbb545eb7c93da1be7c43483e80f68450b4c07c1ff1520bfa3119aaf148348c398ab24ead02b2dade1f6b06e220c5c40e02036c7fe46c1e28fc2d5
6
+ metadata.gz: 27020172c648b060af7a24b08f23d9ab8a3a1cf6a1b8c24a8b5f9547b2bd3ccbb2be5fdecb2b8caa5b7696800b160e82268f0bfb30ed340a7fa80713b198e638
7
+ data.tar.gz: 49cf0c76cf8f38f4d68ac06584fbe4e9b2e0a778c73926ac345f37885452482fbae10d81724392befe19de170f1021d85e87c0fd54b63d2f9968389b8be379e7
data/Gemfile.lock CHANGED
@@ -1,27 +1,27 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- thrift_rack (0.2.5)
4
+ thrift_rack (0.2.6)
5
5
  net-http-persistent (>= 3.0)
6
6
  rack (>= 2.0.6)
7
7
  redis (>= 3.0)
8
- thrift (~> 0.10.0)
8
+ thrift (~> 0.10)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
13
  coderay (1.1.2)
14
- connection_pool (2.2.2)
14
+ connection_pool (2.2.5)
15
15
  method_source (0.9.0)
16
- net-http-persistent (3.0.1)
16
+ net-http-persistent (4.0.1)
17
17
  connection_pool (~> 2.2)
18
18
  pry (0.11.3)
19
19
  coderay (~> 1.1.0)
20
20
  method_source (~> 0.9.0)
21
- rack (2.0.7)
22
- rake (10.5.0)
23
- redis (4.1.2)
24
- thrift (0.10.0.0)
21
+ rack (2.2.3)
22
+ rake (13.0.1)
23
+ redis (4.4.0)
24
+ thrift (0.14.2)
25
25
 
26
26
  PLATFORMS
27
27
  ruby
@@ -29,8 +29,8 @@ PLATFORMS
29
29
  DEPENDENCIES
30
30
  bundler (~> 1.16)
31
31
  pry (~> 0)
32
- rake (~> 10.0)
32
+ rake (~> 13.0)
33
33
  thrift_rack!
34
34
 
35
35
  BUNDLED WITH
36
- 1.16.6
36
+ 1.17.3
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # ThriftRack
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/thrift_rack`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ ThriftRack implements [thrift]([https://thrift.apache.org](https://thrift.apache.org/)) `Compact Protocol + HTTP Transport ` with rack, and makes it easy to write a server with convention.
6
4
 
7
5
  ## Installation
8
6
 
@@ -22,7 +20,207 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ ### Server
24
+
25
+ Assume you use rails only with `activemodel`、`activerecord`、`activesupport`. Because ThriftRack act as controller and view, you do not need `actionview` and `actionpack`
26
+
27
+ You cloud new a rails app use this command
28
+
29
+ ```bash
30
+ rails new demo --skip-action-mailer --skip-action-mailbox --skip-action-text --skip-active-record --skip-active-storage --skip-action-cable --skip-sprockets --skip-javascript --skip-turbolinks --skip-test --skip-system-test --skip-bootsnap --api --skip-webpack-install
31
+ ```
32
+
33
+ Suppose you has a thrift named `math.thrift` to add two number:
34
+
35
+ ```thrift
36
+ # math.thrift
37
+ namespace rb thrift.math # namesapce should same with filename
38
+
39
+ service MathService { # Math is capitalized from Math
40
+ int add(1: int i, 2: int j)
41
+ }
42
+ ```
43
+
44
+ then you should implement this thrift in `math_server.rb`
45
+
46
+ ```ruby
47
+ class MathServer < ThriftRack::Server
48
+ def add(i, j)
49
+ i + j
50
+ end
51
+ end
52
+ ```
53
+
54
+ Then change the `config.ru`
55
+
56
+ ```
57
+ require_relative 'config/environment'
58
+ app = ThriftRack.app(ThriftRack::Server.children)
59
+ run app
60
+ ```
61
+
62
+ Another config under initializers
63
+
64
+ ```ruby
65
+ #initializers/thrift.rb
66
+ Dir["#{Rails.root}/lib/thrift/**/*.rb"].each { |file| require file } # support generate thrift files under lib/thrift
67
+ Dir["#{Rails.root}/app/servers/*.rb"].each { |file| require file } # support servers under app/servers
68
+
69
+ ThriftRack.redis = Redis.new
70
+ ThriftRack::Logger.tag = { key: value} # tag to logs
71
+
72
+ at_exit do
73
+ ThriftRack::Logger.logger.close
74
+ end
75
+ ```
76
+
77
+ Then run this bash
78
+
79
+ ```
80
+ rackup
81
+ ```
82
+
83
+ what happend?
84
+
85
+ * We implement the math.thrift with `POST` method at `/math` path
86
+ * A Server seems like a controller, except that you do not need to write routes.
87
+ * We replace the default rails rack entrance, but it still a rack server. **You could use puma to web server, and enjoy puma's advantage**.
88
+ * Client will auto retry with network jitter, Atom ensure each request at most processed once.
89
+ * `/ping` should be use to health check, all request to `/ping` will not be log
90
+ * `ThriftRack::Logger` log each rpc request with json format. You could use ELK to analyze each request
91
+
92
+ ### Client
93
+
94
+ client cloud write like this
95
+
96
+ ```ruby
97
+ class Math
98
+ attr_accessor :client
99
+ def initialize(request_id = "no-request-id") # web should has one request_id
100
+ @client = ThriftRack::Client.new("http://127.0.0.1:300/math", ThriftClientClass, request_id)
101
+ end
102
+
103
+ def add(i, j)
104
+ self.client.add(i, j)
105
+ end
106
+ end
107
+ ```
108
+
109
+ Another config under initializers
110
+
111
+ ```ruby
112
+ #initializers/thrift.rb
113
+ Dir["#{Rails.root}/lib/thrift/**/*.rb"].each { |file| require file }
114
+
115
+ ThriftRack::Client.config Rails.application.class.parent.name.underscore
116
+ ```
117
+
118
+ what happend?
119
+
120
+ * Client will auto generate a `rpc_id` to tracer rpc request
121
+ * Client will add app_name to header
122
+ * Client use HTTP 1.1, wich persistent tcp connection with multi http requests
123
+ * Client has a connection pool, network error will auto retry
124
+ * Client will log each rpc process time
125
+
126
+ #### Furthermore
127
+
128
+ you chould write a supperclass like under, other client inherit superclass
129
+
130
+ 1. you could write a around_action to set request
131
+
132
+ ```ruby
133
+ class ApplicationController < ActionController::API
134
+ around_action :set_thread_local_request
135
+
136
+ private
137
+
138
+ def set_thread_local_request
139
+ Thread.current["request"] = request
140
+ yield
141
+ ensure
142
+ Thread.current["request"] = nil
143
+ end
144
+ end
145
+ ```
146
+
147
+ 2. write a superclass
148
+
149
+ ```ruby
150
+ class ClientBase
151
+ def initialize(req = nil)
152
+ if req
153
+ @request_id = req.request_id
154
+ end
155
+ end
156
+
157
+ def request_id
158
+ @request_id ||= Thread.current["request"] ? Thread.current["request"].request_id : "no-request-id"
159
+ end
160
+
161
+ def client
162
+ ThriftRack::Client.new("http:127.0.0.1:3000/#{_namespace.underscore}", _client_class, request_id)
163
+ end
164
+
165
+ def respond_to_missing?(method, include_private = false)
166
+ self.client.respond_to?(method)
167
+ end
168
+
169
+ def method_missing(method, *args)
170
+ return super unless self.client.respond_to?(method)
171
+ self.class_eval do
172
+ define_method method.to_sym do |*params|
173
+ self.client.public_send(method, *params)
174
+ end
175
+ end
176
+ self.public_send(method, *args)
177
+ end
178
+
179
+ private
180
+
181
+ def _namespace
182
+ @namespace ||= self.class.name
183
+ end
184
+
185
+ def _client_class
186
+ "Thrift::#{_namespace}::#{_namespace}Service::Client".constantize
187
+ end
188
+
189
+ class << self
190
+ def default
191
+ self.new
192
+ end
193
+
194
+ def respond_to_missing?(method, include_private = false)
195
+ self.default.respond_to?(method)
196
+ end
197
+
198
+ def method_missing(method, *params)
199
+ return super unless self.default.respond_to?(method)
200
+ define_singleton_method method.to_sym do |*args|
201
+ self.default.public_send(method, *args)
202
+ end
203
+ self.public_send(method, *params)
204
+ end
205
+ end
206
+ end
207
+ ```
208
+
209
+ 3. inherit super class
210
+
211
+ ```ruby
212
+ class Math < ClientBase
213
+ def add(i, j)
214
+ self.client.add(i, j)
215
+ end
216
+ end
217
+ ```
218
+
219
+ 4. use
220
+
221
+ ```
222
+ Math.add(1, 2) # will auto assign request_id is with request
223
+ ```
26
224
 
27
225
  ## Development
28
226
 
@@ -0,0 +1,13 @@
1
+ class ThriftRack
2
+ class ActiveRecord
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def call(env)
8
+ ::ActiveRecord::Base.connection_pool.with_connection do
9
+ @app.call(env)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,3 @@
1
- require 'redis'
2
1
  class ThriftRack
3
2
  class Atom
4
3
  def initialize(app)
@@ -9,7 +8,10 @@ class ThriftRack
9
8
  req = Rack::Request.new(env)
10
9
  rpc_id = req.env["HTTP_X_RPC_ID"]
11
10
  if rpc_id
12
- if ThriftRack::Atom.redis.set("thrift_request:#{rpc_id}", true, nx: true, ex: 600)
11
+ start_time = Time.now
12
+ valid = ThriftRack.redis.set("thrift_rack:atom:#{rpc_id}", true, nx: true, ex: 180)
13
+ if valid
14
+ env["ATOM_DURATION"] = ((Time.now - start_time) * 1000).round(4)
13
15
  @app.call(env)
14
16
  else
15
17
  [409, {}, ["RPC Request Processed"]]
@@ -20,10 +22,9 @@ class ThriftRack
20
22
  end
21
23
 
22
24
  class << self
23
- attr_accessor :redis
24
-
25
- def redis
26
- @redis ||= Redis.new
25
+ # compatibility with old version
26
+ def redis=(r)
27
+ ThriftRack.redis = r
27
28
  end
28
29
  end
29
30
  end
@@ -1,8 +1,14 @@
1
1
  require 'securerandom'
2
2
  class ThriftRack
3
3
  class Client
4
- def initialize(url, client_klass, request_id = nil)
5
- @request_id = request_id || "no-request"
4
+ DEFAULT_REQUEST_ID = "no-request".freeze
5
+ def initialize(url, client_klass, request = nil)
6
+ if request.is_a?(ActionDispatch::Request)
7
+ @request = request
8
+ @request_id = request.request_id
9
+ else
10
+ @request_id = request || DEFAULT_REQUEST_ID
11
+ end
6
12
  @url = url
7
13
  @transport = ThriftRack::HttpClientTransport.new(url)
8
14
  protocol = protocol_factory.get_protocol(@transport)
@@ -25,20 +31,38 @@ class ThriftRack
25
31
  begin
26
32
  rpc_id = SecureRandom.uuid
27
33
  request_at = Time.now
28
- @transport.add_headers("X-Request-ID" => @request_id, "X-Rpc-ID" => rpc_id, "X-Rpc-Func" => method.to_s, "X-From" => ThriftRack::Client.app_name || "unknown")
34
+ if Thread.current["RPC_FULL_TRACE"].to_s == "true"
35
+ full_trace = true
36
+ else
37
+ full_trace = @request_id == DEFAULT_REQUEST_ID || @request_id.hash % 8 == 0
38
+ end
39
+ @transport.add_headers("X-Request-ID" => @request_id, "X-Rpc-ID" => rpc_id, "X-Rpc-Func" => method.to_s, "X-From" => ThriftRack::Client.app_name || "unknown", "X-Full-Trace" => full_trace.to_s)
29
40
  @client.send(method, *args)
30
41
  ensure
31
42
  end_time = Time.now
32
- ThriftRack::Client.logger.info(
33
- JSON.dump(
34
- request_at: request_at.iso8601(6),
35
- request_id: @request_id,
36
- rpc_id: rpc_id,
37
- duration: ((end_time - request_at) * 1000).round(4),
38
- path: URI(@url).path,
39
- func: method,
40
- ),
41
- )
43
+ duration = (end_time - request_at) * 1000
44
+ process_duration = @transport.response_headers["x-server-process-duration"]&.to_f
45
+ if full_trace || duration >= 100
46
+ ThriftRack::Client.logger.info(
47
+ JSON.dump(
48
+ request_at: request_at.iso8601(6),
49
+ request_id: @request_id,
50
+ rpc_id: rpc_id,
51
+ duration: duration.round(4),
52
+ path: URI(@url).path,
53
+ func: method,
54
+ tag: ThriftRack::Client.logger_tag,
55
+ full_trace: full_trace,
56
+ extra_context: @request ? { context: "action_controller", controller: @request.params["controller"], action: @request.params["action"] } : {},
57
+ server: {
58
+ id: @transport.response_headers["x-server-id"],
59
+ private_ip: @transport.response_headers["x-server-private-ip"],
60
+ process_duration: process_duration ? process_duration.round(4) : nil,
61
+ network_duration: process_duration ? (duration - process_duration).round(4) : nil,
62
+ },
63
+ ),
64
+ )
65
+ end
42
66
  end
43
67
  end
44
68
  end
@@ -46,8 +70,16 @@ class ThriftRack
46
70
  end
47
71
 
48
72
  class << self
49
- attr_accessor :app_name
50
- attr_reader :pool_size
73
+ attr_writer :app_name, :logger_tag
74
+
75
+ def app_name
76
+ @app_name ||= Rails.application.class.parent.name.underscore if defined? Rails
77
+ @app_name
78
+ end
79
+
80
+ def logger_tag
81
+ @logger_tag || {}
82
+ end
51
83
 
52
84
  def logger
53
85
  @logger ||= if defined? Rails
@@ -57,13 +89,13 @@ class ThriftRack
57
89
  end
58
90
  end
59
91
 
60
- def pool_size=(p)
61
- http = Net::HTTP::Persistent.new(name: self.app_name, pool_size: p)
62
- http.retry_change_requests = true
63
- http.max_requests = 100
64
- http.verify_mode = 0
65
- HttpClientTransport.default = http
66
- @pool_size = p
92
+ def config(app_name, max_requests: 100, logger_tag: {})
93
+ self.app_name = app_name
94
+ self.logger_tag = logger_tag
95
+ HttpClientTransport.default = HttpClientTransport.new_http(app_name, max_requests: max_requests)
96
+ at_exit do
97
+ ThriftRack::Client.logger.close
98
+ end
67
99
  end
68
100
  end
69
101
  end
@@ -0,0 +1,46 @@
1
+ class ThriftRack
2
+ class Downgrade
3
+ def initialize(app)
4
+ @app = app
5
+ @drop_percentage = 0
6
+ @last_sync_drop_percentage_at = Time.at(0)
7
+ end
8
+
9
+ def call(env)
10
+ if rand(100) < drop_percentage
11
+ [509, {}, ["Downgrading"]]
12
+ else
13
+ @app.call(env)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def drop_percentage
20
+ if Time.now - @last_sync_drop_percentage_at > 3
21
+ @last_sync_drop_percentage_at = Time.now
22
+ @drop_percentage = self.class.current_drop_percentage
23
+ else
24
+ @drop_percentage
25
+ end
26
+ end
27
+
28
+ class << self
29
+ def change_downgrade(drop_percentage)
30
+ ThriftRack.redis.set(downgrade_redis_key, drop_percentage)
31
+ end
32
+
33
+ def current_drop_percentage
34
+ ThriftRack.redis.get(downgrade_redis_key).to_f
35
+ end
36
+
37
+ def close_downgrade
38
+ ThriftRack.redis.del(downgrade_redis_key)
39
+ end
40
+
41
+ def downgrade_redis_key
42
+ "thrift_rack:downgrade"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -6,7 +6,7 @@ class ThriftRack
6
6
 
7
7
  def call(env)
8
8
  req = Rack::Request.new(env)
9
- return Rack::Response.new(["Not Valid Thrift Request"], 400, {'Content-Type' => 'text/plain'}) unless req.post? && req.env["CONTENT_TYPE"] == THRIFT_HEADER
9
+ return 400, {'Content-Type' => 'text/plain'}, ["Not Valid Thrift Request"] unless req.post? && req.env["CONTENT_TYPE"] == THRIFT_HEADER
10
10
  @app.call(env)
11
11
  end
12
12
  end
@@ -4,10 +4,14 @@ require 'net/http/persistent'
4
4
  class ThriftRack
5
5
  class HttpClientTransport < Thrift::BaseTransport
6
6
  class RespCodeError < StandardError; end
7
- class ProcessedRequest < StandardError; end
7
+ class ProcessedRequest < RespCodeError; end
8
+ class ServerDowngradingError < RespCodeError; end
9
+
10
+ attr_accessor :response_headers
8
11
  def initialize(url, opts = {})
9
12
  @headers = {'Content-Type' => 'application/x-thrift'}
10
13
  @outbuf = Thrift::Bytes.empty_byte_buffer
14
+ @response_headers = {}
11
15
  @url = url
12
16
  end
13
17
 
@@ -19,19 +23,23 @@ class ThriftRack
19
23
  @headers = @headers.merge(headers)
20
24
  end
21
25
 
22
-
23
26
  def flush
27
+ self.response_headers = {}
24
28
  uri = URI(@url)
25
29
  post = Net::HTTP::Post.new uri.path
26
30
  post.body = @outbuf
27
31
  post.initialize_http_header(@headers)
28
32
  resp = retry_request_with_503{ThriftRack::HttpClientTransport.default.request(uri, post)}
29
33
  data = resp.body
30
- if resp.code.to_i != 200
31
- if resp.code.to_i == 409
32
- raise ProcessedRequest.new(@url)
34
+ self.response_headers = resp.header
35
+ resp_code = resp.code.to_i
36
+ if resp_code != 200
37
+ if resp_code == 409
38
+ raise ProcessedRequest, @url
39
+ elsif resp_code == 509
40
+ raise ServerDowngradingError, @url
33
41
  else
34
- raise RespCodeError.new("#{resp.code} on #{@url} with body #{data}")
42
+ raise RespCodeError, "#{resp.code} on #{@url} with body #{data}"
35
43
  end
36
44
  end
37
45
  data = Thrift::Bytes.force_binary_encoding(data)
@@ -44,9 +52,8 @@ class ThriftRack
44
52
  resp = nil
45
53
  3.times do |i|
46
54
  resp = yield
47
- if resp.code.to_i != 503
48
- return resp
49
- end
55
+ return resp unless resp.code.to_i == 503
56
+
50
57
  sleep(0.1 * i)
51
58
  ThriftRack::HttpClientTransport.default.reconnect
52
59
  end
@@ -57,12 +64,14 @@ class ThriftRack
57
64
  attr_accessor :default
58
65
 
59
66
  def default
60
- return @default if @default
61
- @default = Net::HTTP::Persistent.new
62
- @default.retry_change_requests = true
63
- @default.max_requests = 100
64
- @default.verify_mode = 0
65
- @default
67
+ @default ||= new_http(ThriftRack::Client.app_name || "default")
68
+ end
69
+
70
+ def new_http(name, max_requests: 100)
71
+ http = Net::HTTP::Persistent.new(name: name)
72
+ http.max_requests = max_requests
73
+ http.verify_mode = 0
74
+ http
66
75
  end
67
76
  end
68
77
  end
@@ -8,23 +8,35 @@ class ThriftRack
8
8
 
9
9
  def call(env)
10
10
  request_at = env['LAUNCH_AT'] || Time.now
11
+ income_middleware_duration = Time.now - request_at
11
12
  req = Rack::Request.new(env)
12
13
  resp = @app.call(env)
13
14
  resp
14
15
  ensure
15
- end_time = Time.now
16
- ThriftRack::Logger.logger.info(
17
- JSON.dump(
18
- request_at: request_at.iso8601(6),
19
- request_id: req.env["HTTP_X_REQUEST_ID"],
20
- rpc_id: req.env["HTTP_X_RPC_ID"],
21
- duration: ((end_time - request_at) * 1000).round(4),
22
- path: req.path,
23
- func: req.env["HTTP_X_RPC_FUNC"],
24
- from: req.env["HTTP_X_FROM"],
25
- tag: Logger.tag,
26
- ),
27
- )
16
+ duration = ((Time.now - request_at) * 1000).round(4)
17
+ request_id = req.env["HTTP_X_REQUEST_ID"]
18
+ if req.env["HTTP_X_FULL_TRACE"]
19
+ full_trace = req.env["HTTP_X_FULL_TRACE"] == "true"
20
+ else
21
+ full_trace = request_id.hash % 8 == 0
22
+ end
23
+ if full_trace || duration >= 100
24
+ ThriftRack::Logger.logger.info(
25
+ JSON.dump(
26
+ request_at: request_at.iso8601(6),
27
+ request_id: request_id,
28
+ rpc_id: req.env["HTTP_X_RPC_ID"],
29
+ duration: duration,
30
+ income_middleware_duration: (income_middleware_duration * 1000).round(2),
31
+ atom_duration: env["ATOM_DURATION"],
32
+ path: req.path,
33
+ func: req.env["HTTP_X_RPC_FUNC"],
34
+ from: req.env["HTTP_X_FROM"],
35
+ full_trace: full_trace,
36
+ tag: Logger.tag,
37
+ ),
38
+ )
39
+ end
28
40
  end
29
41
 
30
42
  class << self
@@ -6,7 +6,7 @@ class ThriftRack
6
6
 
7
7
  def call(env)
8
8
  req = Rack::Request.new(env)
9
- return Rack::Response.new(["PONG"], 200, {'Content-Type' => 'text/plain'}) if req.path == "/ping"
9
+ return 200, {'Content-Type' => 'text/plain'}, ["PONG"] if req.path == "/ping"
10
10
  @app.call(env)
11
11
  end
12
12
  end
@@ -1,5 +1,9 @@
1
1
  class ThriftRack
2
2
  class Server
3
+ def initialize(request = nil)
4
+ @_request = request
5
+ end
6
+
3
7
  class << self
4
8
  def inherited(subclass)
5
9
  warn "Your class should end with Server not it is #{subclass}" unless subclass.name.end_with?("Server")
@@ -22,7 +26,7 @@ class ThriftRack
22
26
  if Kernel.const_defined?(promissory_class_name)
23
27
  Kernel.const_get(promissory_class_name)
24
28
  else
25
- raise "You should overwrite processor_class for #{self.class}"
29
+ raise "You should overwrite processor_class for #{self}"
26
30
  end
27
31
  end
28
32
 
@@ -0,0 +1,28 @@
1
+ class ThriftRack
2
+ class ServerMetric
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def call(env)
8
+ request_at = env['LAUNCH_AT'] || Time.now
9
+ status, headers, body = @app.call(env)
10
+ headers["x-server-process-duration"] = ((Time.now - request_at) * 1000).to_s
11
+ headers["x-server-id"] = self.class.server_id
12
+ headers["x-server-private-ip"] = self.class.server_private_ip
13
+ [status, headers, body]
14
+ end
15
+
16
+ class << self
17
+ attr_writer :server_id, :server_private_ip
18
+
19
+ def server_id
20
+ @server_id || "unkonwn"
21
+ end
22
+
23
+ def server_private_ip
24
+ @server_private_ip || "0.0.0.0"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  class ThriftRack
2
- VERSION = "0.2.5"
2
+ VERSION = "0.2.6"
3
3
  end
data/lib/thrift_rack.rb CHANGED
@@ -7,13 +7,17 @@ require 'thrift_rack/launch_timestamp'
7
7
  require 'thrift_rack/ping'
8
8
  require 'thrift_rack/atom'
9
9
  require 'thrift_rack/format_check'
10
+ require 'thrift_rack/server_metric'
10
11
  require 'thrift_rack/http_client_transport'
12
+ require 'thrift_rack/downgrade'
13
+ require 'thrift_rack/active_record'
11
14
 
12
15
  require 'rack'
13
16
  require 'thrift'
17
+ require 'redis'
14
18
 
15
19
  class ThriftRack
16
- THRIFT_HEADER = "application/x-thrift"
20
+ THRIFT_HEADER = "application/x-thrift".freeze
17
21
 
18
22
  def initialize(servers = nil)
19
23
  servers ||= ThriftRack::Server.children
@@ -27,27 +31,39 @@ class ThriftRack
27
31
  req = Rack::Request.new(env)
28
32
  Thread.current["request"] = req
29
33
  server_class = @maps[req.path]
30
- return Rack::Response.new(["No Thrift Server For #{req.path}"], 404, {'Content-Type' => 'text/plain'}) unless server_class
34
+ return 400, { 'Content-Type' => 'text/plain' }, ["No Thrift Server For #{req.path}"] unless server_class
31
35
 
32
- resp = Rack::Response.new([], 200, {'Content-Type' => THRIFT_HEADER})
36
+ resp = Rack::Response.new([], 200, { 'Content-Type' => THRIFT_HEADER })
33
37
 
34
38
  transport = Thrift::IOStreamTransport.new req.body, resp
35
39
  protocol = server_class.protocol_factory.get_protocol transport
36
- server_class.processor_class.new(server_class.new).process(protocol, protocol)
40
+ server_class.processor_class.new(server_class.new(req)).process(protocol, protocol)
37
41
 
38
- resp
42
+ resp_a = resp.to_a
43
+ [resp_a[0], resp_a[1], [resp_a[2].join]]
39
44
  ensure
40
45
  Thread.current["request"] = nil
41
46
  end
47
+ class << self
48
+ attr_writer :redis
42
49
 
43
- def self.app(servers = nil)
44
- Rack::Builder.new(ThriftRack.new(servers)) do
45
- use ThriftRack::LaunchTimestamp
46
- use ThriftRack::Ping
47
- use ThriftRack::FormatCheck
48
- use ThriftRack::Atom
49
- use ThriftRack::Logger
50
- use ThriftRack::Sentry if defined? Raven
50
+ def app(servers = nil)
51
+ Rack::Builder.new(ThriftRack.new(servers)) do
52
+ use ThriftRack::LaunchTimestamp
53
+ use ThriftRack::ActiveRecord if defined? ::ActiveRecord::Base
54
+ # use(ActionDispatch::Executor, ::Rails.application.executor) if defined? ::Rails
55
+ use ThriftRack::Downgrade
56
+ use ThriftRack::Ping
57
+ use ThriftRack::FormatCheck
58
+ use ThriftRack::Atom
59
+ use ThriftRack::Logger
60
+ use ThriftRack::Sentry if defined? Raven
61
+ use ThriftRack::ServerMetric
62
+ end
63
+ end
64
+
65
+ def redis
66
+ @redis ||= Redis.new
51
67
  end
52
68
  end
53
69
  end
data/thrift_rack.gemspec CHANGED
@@ -22,11 +22,11 @@ Gem::Specification.new do |spec|
22
22
  spec.require_paths = ["lib"]
23
23
 
24
24
  spec.add_dependency "rack", ">= 2.0.6"
25
- spec.add_dependency "thrift", '~> 0.10.0'
25
+ spec.add_dependency "thrift", '~> 0.10'
26
26
  spec.add_dependency 'net-http-persistent', ">= 3.0"
27
27
  spec.add_dependency 'redis', '>=3.0'
28
28
 
29
29
  spec.add_development_dependency "bundler", "~> 1.16"
30
- spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rake", "~> 13.0"
31
31
  spec.add_development_dependency "pry", "~> 0"
32
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thrift_rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - xuxiangyang
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-11 00:00:00.000000000 Z
11
+ date: 2021-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.10.0
33
+ version: '0.10'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.10.0
40
+ version: '0.10'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: net-http-persistent
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '10.0'
89
+ version: '13.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '10.0'
96
+ version: '13.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: pry
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -125,8 +125,10 @@ files:
125
125
  - config.ru
126
126
  - lib/config.ru
127
127
  - lib/thrift_rack.rb
128
+ - lib/thrift_rack/active_record.rb
128
129
  - lib/thrift_rack/atom.rb
129
130
  - lib/thrift_rack/client.rb
131
+ - lib/thrift_rack/downgrade.rb
130
132
  - lib/thrift_rack/format_check.rb
131
133
  - lib/thrift_rack/http_client_transport.rb
132
134
  - lib/thrift_rack/launch_timestamp.rb
@@ -134,13 +136,14 @@ files:
134
136
  - lib/thrift_rack/ping.rb
135
137
  - lib/thrift_rack/sentry.rb
136
138
  - lib/thrift_rack/server.rb
139
+ - lib/thrift_rack/server_metric.rb
137
140
  - lib/thrift_rack/version.rb
138
141
  - thrift_rack.gemspec
139
142
  homepage: https://github.com/xuxiangyang/thrift_rack
140
143
  licenses:
141
144
  - MIT
142
145
  metadata: {}
143
- post_install_message:
146
+ post_install_message:
144
147
  rdoc_options: []
145
148
  require_paths:
146
149
  - lib
@@ -155,9 +158,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
158
  - !ruby/object:Gem::Version
156
159
  version: '0'
157
160
  requirements: []
158
- rubyforge_project:
159
- rubygems_version: 2.7.9
160
- signing_key:
161
+ rubygems_version: 3.0.8
162
+ signing_key:
161
163
  specification_version: 4
162
164
  summary: thrift http rakc server
163
165
  test_files: []