logstash-input-http 3.0.7 → 3.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0cfc2c0ffdec2163b2bd28db4cac5e12509396828a8ed59ea768372a13c2726
4
- data.tar.gz: 82bc2c8ae080551d5f3046870c26f0b28761a4ad9fbd9c716ca2a877a8dcc5f4
3
+ metadata.gz: 1975dd1f7608f77b01121212cb01df2a95c23eef97b40613ea1b5161bebe8772
4
+ data.tar.gz: 2de2626b158b0ee92fded043dfb6f32c11c0fdab2c515972157ef48e6e10a5cb
5
5
  SHA512:
6
- metadata.gz: '06696c71d5be92acffde997e3f5f3cd591acb06bbe14237c70fa68e30343cd4a84f6323f8c826eb17d63afb08397aee162bfc414bda63f02f80f1ab039dc1e8c'
7
- data.tar.gz: 7990cf7ed10d3e0b723becc3d01efb3da51f10c2fc895e0b8d8614dc4f87f2d0ce4f45c7fca0c675dd204cad27f42eaaffcd78067eb9adff9e21153f465324f8
6
+ metadata.gz: b1088e09605455d87a480afdeaf1b41aa1bae213b5cdb3ee91def0180589251b45748a6c3980eb895d24511c1371f71ac0546a5ce0b72849dd5f9fbe89f285cc
7
+ data.tar.gz: db68457ace06371dcaa312a9a2fa2ad3d96a7cfd1fe047a7e0c8cfed3a0a43c36521a73bf3d15fc39cdf947faf1b1f2f7ad590ea6c546cbb44df5b5bea3b7f8f
@@ -1,3 +1,6 @@
1
+ ## 3.0.8
2
+ - In the event that all webserver threads are busy this plugin will now return a 429, busy, error.
3
+
1
4
  ## 3.0.7
2
5
  - Update gemspec summary
3
6
 
@@ -31,6 +31,19 @@ This input can also be used to receive webhook requests to integrate with other
31
31
  and applications. By taking advantage of the vast plugin ecosystem available in Logstash
32
32
  you can trigger actionable events right from your application.
33
33
 
34
+ ==== Blocking Behavior
35
+
36
+ The HTTP protocol doesn't deal well with long running requests. This plugin will either return
37
+ a 429 (busy) error when Logstash is backlogged, or it will time out the request.
38
+
39
+ If a 429 error is encountered clients should sleep, backing off exponentially with some random
40
+ jitter, then retry their request.
41
+
42
+ This plugin will block if the Logstash queue is blocked and there are available HTTP input threads.
43
+ This will cause most HTTP clients to time out. Sent events will still be processed in this case. This
44
+ behavior is not optimal and will be changed in a future release. In the future, this plugin will always
45
+ return a 429 if the queue is busy, and will not time out in the event of a busy queue.
46
+
34
47
  ==== Security
35
48
  This plugin supports standard HTTP basic authentication headers to identify the requester.
36
49
  You can pass in a username, password combination while sending data to this input
@@ -120,16 +120,24 @@ class LogStash::Inputs::Http < LogStash::Inputs::Base
120
120
  @server.add_tcp_listener(@host, @port)
121
121
  end
122
122
  @server.min_threads = 0
123
- @server.max_threads = @threads
123
+ # The actual number of threads is one higher to let us reject additional requests
124
+ @server.max_threads = @threads + 1
124
125
  @codecs = Hash.new
126
+
125
127
  @additional_codecs.each do |content_type, codec|
126
128
  @codecs[content_type] = LogStash::Plugin.lookup("codec", codec).new
127
129
  end
128
- @codec_lock = java.util.concurrent.locks.ReentrantLock.new
130
+
131
+ @write_slots = java.util.concurrent.ArrayBlockingQueue.new(threads)
132
+ threads.times do
133
+ # Freeze these guys just in case, since they aren't threadsafe
134
+ @write_slots.put(Hash[@codecs.map {|k,v| [k.freeze, v.clone].freeze }.freeze].freeze)
135
+ end
136
+
129
137
  end # def register
130
138
 
139
+ BUSY_RESPONSE = ['Server busy, please retry request later'.freeze].freeze
131
140
  def run(queue)
132
-
133
141
  # proc needs to be defined at this context
134
142
  # to capture @codecs, @logger and lowercase_keys
135
143
  p = Proc.new do |req|
@@ -138,16 +146,20 @@ class LogStash::Inputs::Http < LogStash::Inputs::Base
138
146
  REJECTED_HEADERS.each {|k| req.delete(k) }
139
147
  req = lowercase_keys(req)
140
148
  body = req.delete("rack.input")
141
- @codec_lock.lock
149
+ local_codecs = @write_slots.poll()
150
+ if !local_codecs # No free write slot
151
+ next [429, {}, BUSY_RESPONSE]
152
+ end
142
153
  begin
143
- @codecs.fetch(req["content_type"], @codec).decode(body.read) do |event|
154
+ codec = local_codecs.fetch(req["content_type"], @codec)
155
+ codec.decode(body.read) do |event|
144
156
  event.set("host", remote_host)
145
157
  event.set("headers", req)
146
158
  decorate(event)
147
159
  queue << event
148
160
  end
149
161
  ensure
150
- @codec_lock.unlock
162
+ @write_slots.put(local_codecs)
151
163
  end
152
164
  ['200', @response_headers, ['ok']]
153
165
  rescue => e
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-input-http'
3
- s.version = '3.0.7'
3
+ s.version = '3.0.8'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = "Receives events over HTTP or HTTPS"
6
6
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -25,13 +25,39 @@ describe LogStash::Inputs::Http do
25
25
  end
26
26
 
27
27
  describe "request handling" do
28
- subject { LogStash::Inputs::Http.new }
28
+ subject { LogStash::Inputs::Http.new() }
29
29
  before :each do
30
30
  subject.register
31
31
  t = Thread.new { subject.run(queue) }
32
32
  sleep 0.01 until subject.instance_variable_get(:@server).running == 0
33
33
  end
34
34
 
35
+ describe "handling overflowing requests with a 429" do
36
+ let(:queue) { SizedQueue.new(1) }
37
+ let(:options) { { "threads" => 2 } }
38
+
39
+ def do_post
40
+ FTW::Agent.new.post!("http://localhost:8080/meh.json",
41
+ :headers => { "content-type" => "text/plain" },
42
+ :body => "hello")
43
+ end
44
+
45
+ context "when sending more requests than than queue slots" do
46
+ it "should block when the queue is full" do
47
+ threads = (subject.threads+5).times.map do # Add one request to the queue then fill the two slots
48
+ Thread.new { do_post } # These threads should block
49
+ end
50
+
51
+ expect(do_post.status).to eq(429)
52
+
53
+ Thread.new do
54
+ while queue.pop
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
35
61
  it "should include remote host in \"host\" property" do
36
62
  agent.post!("http://localhost:8080/meh.json",
37
63
  :headers => { "content-type" => "text/plain" },
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.7
4
+ version: 3.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-07 00:00:00.000000000 Z
11
+ date: 2017-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -175,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
175
  version: '0'
176
176
  requirements: []
177
177
  rubyforge_project:
178
- rubygems_version: 2.6.11
178
+ rubygems_version: 2.6.13
179
179
  signing_key:
180
180
  specification_version: 4
181
181
  summary: Receives events over HTTP or HTTPS