launchdarkly-server-sdk 5.7.1 → 5.7.2

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
  SHA1:
3
- metadata.gz: 35e90a3d6853e2a12b8cf6d3c44a5d84c397b76a
4
- data.tar.gz: 58a0229a7f331cb619568c8095a9381c60753a24
3
+ metadata.gz: 3dd5750bde3461f500b79c5542aa1e7bd3c0f54a
4
+ data.tar.gz: 5f83fba1e17f45975823cae9a6d011a3e4ef22ec
5
5
  SHA512:
6
- metadata.gz: 4c2c1b2598e1ccf4a5f7f49fb4ef39974938100b4b9ea28fe910d7aea8a153d09a8e8ee978794293958c6040208fd055b271e1a4c8f4f3245e94dcc3d7c51812
7
- data.tar.gz: 4d0eadc0f93a217d36f89fae7b2f5b19ce5fa78f98c36a81d6d50d782ac7fed3f451384599bb24c7b8cec80e2e0a26df42d1dd1fcbe7ce6d29906f314fd929e7
6
+ metadata.gz: eb39d85a5ad9f752729e0ebf0431c4c76b7b23c9fabec7d9494cfef30946f10f9c8e6a4f3d575fb1d9203c4ad21c53e4db796e878be173f306ae74f3c3c5c5a7
7
+ data.tar.gz: '07278a34c36c2f952a0e1c503f019959cbd0b45ba13c6cc021cc8a83ddd2895df5650e7c5adafe3ad0bea6e09497831d21581b74ccffd9e3f236770548ea44c8'
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to the LaunchDarkly Ruby SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
4
4
 
5
+ ## [5.7.1] - 2020-03-18
6
+ ### Fixed:
7
+ - The backoff delay logic for reconnecting after a stream failure was broken so that if a failure occurred after a stream had been active for at least 60 seconds, retries would use _no_ delay, potentially causing a flood of requests and a spike in CPU usage. This bug was introduced in version 5.5.0 of the SDK.
8
+
5
9
  ## [5.7.0] - 2020-03-10
6
10
  ### Added:
7
11
  - The SDK now periodically sends diagnostic data to LaunchDarkly, describing the version and configuration of the SDK, the architecture and version of the runtime platform, and performance statistics. No credentials, hostnames, or other identifiable values are included. This behavior can be disabled with `Config.diagnostic_opt_out` or configured with `Config.diagnostic_recording_interval`.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- launchdarkly-server-sdk (5.7.1)
4
+ launchdarkly-server-sdk (5.7.2)
5
5
  concurrent-ruby (~> 1.0)
6
6
  json (>= 1.8, < 3)
7
7
  ld-eventsource (= 1.0.3)
@@ -319,7 +319,7 @@ module LaunchDarkly
319
319
  success = flush_workers.post do
320
320
  begin
321
321
  events_out = @formatter.make_output_events(payload.events, payload.summary)
322
- result = @event_sender.send_event_data(events_out.to_json, false)
322
+ result = @event_sender.send_event_data(events_out.to_json, "#{events_out.length} events", false)
323
323
  @disabled.value = true if result.must_shutdown
324
324
  if !result.time_from_server.nil?
325
325
  @last_known_past_time.value = (result.time_from_server.to_f * 1000).to_i
@@ -348,7 +348,7 @@ module LaunchDarkly
348
348
  uri = URI(@config.events_uri + "/diagnostic")
349
349
  diagnostic_event_workers.post do
350
350
  begin
351
- @event_sender.send_event_data(event.to_json, true)
351
+ @event_sender.send_event_data(event.to_json, "diagnostic event", true)
352
352
  rescue => e
353
353
  Util.log_exception(@config.logger, "Unexpected error in event processor", e)
354
354
  end
@@ -18,10 +18,9 @@ module LaunchDarkly
18
18
  @retry_interval = retry_interval
19
19
  end
20
20
 
21
- def send_event_data(event_data, is_diagnostic)
21
+ def send_event_data(event_data, description, is_diagnostic)
22
22
  uri = is_diagnostic ? @diagnostic_uri : @events_uri
23
23
  payload_id = is_diagnostic ? nil : SecureRandom.uuid
24
- description = is_diagnostic ? 'diagnostic event' : "#{event_data.length} events"
25
24
  res = nil
26
25
  (0..1).each do |attempt|
27
26
  if attempt > 0
@@ -30,7 +29,7 @@ module LaunchDarkly
30
29
  end
31
30
  begin
32
31
  @client.start if !@client.started?
33
- @logger.debug { "[LDClient] sending #{description}: #{body}" }
32
+ @logger.debug { "[LDClient] sending #{description}: #{event_data}" }
34
33
  req = Net::HTTP::Post.new(uri)
35
34
  req.content_type = "application/json"
36
35
  req.body = event_data
@@ -56,7 +56,7 @@ module LaunchDarkly
56
56
  if @config.offline? || !@config.send_events
57
57
  @event_processor = NullEventProcessor.new
58
58
  else
59
- @event_processor = EventProcessor.new(sdk_key, config, diagnostic_accumulator)
59
+ @event_processor = EventProcessor.new(sdk_key, config, nil, diagnostic_accumulator)
60
60
  end
61
61
 
62
62
  if @config.use_ldd?
@@ -1,3 +1,3 @@
1
1
  module LaunchDarkly
2
- VERSION = "5.7.1"
2
+ VERSION = "5.7.2"
3
3
  end
@@ -27,7 +27,7 @@ module LaunchDarkly
27
27
  with_sender_and_server do |es, server|
28
28
  server.setup_ok_response("/bulk", "")
29
29
 
30
- result = es.send_event_data(fake_data, false)
30
+ result = es.send_event_data(fake_data, "", false)
31
31
 
32
32
  expect(result.success).to be true
33
33
  expect(result.must_shutdown).to be false
@@ -49,8 +49,8 @@ module LaunchDarkly
49
49
  with_sender_and_server do |es, server|
50
50
  server.setup_ok_response("/bulk", "")
51
51
 
52
- result1 = es.send_event_data(fake_data, false)
53
- result2 = es.send_event_data(fake_data, false)
52
+ result1 = es.send_event_data(fake_data, "", false)
53
+ result2 = es.send_event_data(fake_data, "", false)
54
54
  expect(result1.success).to be true
55
55
  expect(result2.success).to be true
56
56
 
@@ -66,7 +66,7 @@ module LaunchDarkly
66
66
  with_sender_and_server do |es, server|
67
67
  server.setup_ok_response("/diagnostic", "")
68
68
 
69
- result = es.send_event_data(fake_data, true)
69
+ result = es.send_event_data(fake_data, "", true)
70
70
 
71
71
  expect(result.success).to be true
72
72
  expect(result.must_shutdown).to be false
@@ -94,7 +94,7 @@ module LaunchDarkly
94
94
 
95
95
  es = make_sender(server)
96
96
 
97
- result = es.send_event_data(fake_data, false)
97
+ result = es.send_event_data(fake_data, "", false)
98
98
 
99
99
  expect(result.success).to be true
100
100
 
@@ -116,7 +116,7 @@ module LaunchDarkly
116
116
  res.status = req_count == 2 ? 200 : status
117
117
  end
118
118
 
119
- result = es.send_event_data(fake_data, false)
119
+ result = es.send_event_data(fake_data, "", false)
120
120
 
121
121
  expect(result.success).to be true
122
122
  expect(result.must_shutdown).to be false
@@ -141,7 +141,7 @@ module LaunchDarkly
141
141
  res.status = req_count == 3 ? 200 : status
142
142
  end
143
143
 
144
- result = es.send_event_data(fake_data, false)
144
+ result = es.send_event_data(fake_data, "", false)
145
145
 
146
146
  expect(result.success).to be false
147
147
  expect(result.must_shutdown).to be false
@@ -164,7 +164,7 @@ module LaunchDarkly
164
164
  res.status = status
165
165
  end
166
166
 
167
- result = es.send_event_data(fake_data, false)
167
+ result = es.send_event_data(fake_data, "", false)
168
168
 
169
169
  expect(result.success).to be false
170
170
  expect(result.must_shutdown).to be true
@@ -578,7 +578,7 @@ describe LaunchDarkly::EventProcessor do
578
578
  @diagnostic_payloads = Queue.new
579
579
  end
580
580
 
581
- def send_event_data(data, is_diagnostic)
581
+ def send_event_data(data, description, is_diagnostic)
582
582
  (is_diagnostic ? @diagnostic_payloads : @analytics_payloads).push(JSON.parse(data, symbolize_names: true))
583
583
  @result
584
584
  end
@@ -0,0 +1,123 @@
1
+ require "http_util"
2
+ require "spec_helper"
3
+
4
+
5
+ SDK_KEY = "sdk-key"
6
+
7
+ USER = { key: 'userkey' }
8
+
9
+ ALWAYS_TRUE_FLAG = { key: 'flagkey', version: 1, on: false, offVariation: 1, variations: [ false, true ] }
10
+ DATA_WITH_ALWAYS_TRUE_FLAG = {
11
+ flags: { ALWAYS_TRUE_FLAG[:key ].to_sym => ALWAYS_TRUE_FLAG },
12
+ segments: {}
13
+ }
14
+ PUT_EVENT_WITH_ALWAYS_TRUE_FLAG = "event: put\ndata:{\"data\":#{DATA_WITH_ALWAYS_TRUE_FLAG.to_json}}\n\n'"
15
+
16
+ def with_client(config)
17
+ client = LaunchDarkly::LDClient.new(SDK_KEY, config)
18
+ begin
19
+ yield client
20
+ ensure
21
+ client.close
22
+ end
23
+ end
24
+
25
+ module LaunchDarkly
26
+ # Note that we can't do end-to-end tests in streaming mode until we have a test server that can do streaming
27
+ # responses, which is difficult in WEBrick.
28
+
29
+ describe "LDClient end-to-end" do
30
+ it "starts in polling mode" do
31
+ with_server do |poll_server|
32
+ poll_server.setup_ok_response("/sdk/latest-all", DATA_WITH_ALWAYS_TRUE_FLAG.to_json, "application/json")
33
+
34
+ config = Config.new(
35
+ stream: false,
36
+ base_uri: poll_server.base_uri.to_s,
37
+ send_events: false,
38
+ logger: NullLogger.new
39
+ )
40
+ with_client(config) do |client|
41
+ expect(client.initialized?).to be true
42
+ expect(client.variation(ALWAYS_TRUE_FLAG[:key], USER, false)).to be true
43
+ end
44
+ end
45
+ end
46
+
47
+ it "fails in polling mode with 401 error" do
48
+ with_server do |poll_server|
49
+ poll_server.setup_status_response("/sdk/latest-all", 401)
50
+
51
+ config = Config.new(
52
+ stream: false,
53
+ base_uri: poll_server.base_uri.to_s,
54
+ send_events: false,
55
+ logger: NullLogger.new
56
+ )
57
+ with_client(config) do |client|
58
+ expect(client.initialized?).to be false
59
+ expect(client.variation(ALWAYS_TRUE_FLAG[:key], USER, false)).to be false
60
+ end
61
+ end
62
+ end
63
+
64
+ it "sends event without diagnostics" do
65
+ with_server do |poll_server|
66
+ with_server do |events_server|
67
+ events_server.setup_ok_response("/bulk", "")
68
+ poll_server.setup_ok_response("/sdk/latest-all", '{"flags":{},"segments":{}}', "application/json")
69
+
70
+ config = Config.new(
71
+ stream: false,
72
+ base_uri: poll_server.base_uri.to_s,
73
+ events_uri: events_server.base_uri.to_s,
74
+ diagnostic_opt_out: true,
75
+ logger: NullLogger.new
76
+ )
77
+ with_client(config) do |client|
78
+ client.identify(USER)
79
+ client.flush
80
+
81
+ req, body = events_server.await_request_with_body
82
+ expect(req.header['authorization']).to eq [ SDK_KEY ]
83
+ data = JSON.parse(body)
84
+ expect(data.length).to eq 1
85
+ expect(data[0]["kind"]).to eq "identify"
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ it "sends diagnostic event" do
92
+ with_server do |poll_server|
93
+ with_server do |events_server|
94
+ events_server.setup_ok_response("/bulk", "")
95
+ events_server.setup_ok_response("/diagnostic", "")
96
+ poll_server.setup_ok_response("/sdk/latest-all", '{"flags":{},"segments":{}}', "application/json")
97
+
98
+ config = Config.new(
99
+ stream: false,
100
+ base_uri: poll_server.base_uri.to_s,
101
+ events_uri: events_server.base_uri.to_s,
102
+ logger: NullLogger.new
103
+ )
104
+ with_client(config) do |client|
105
+ user = { key: 'userkey' }
106
+ client.identify(user)
107
+ client.flush
108
+
109
+ req0, body0 = events_server.await_request_with_body
110
+ req1, body1 = events_server.await_request_with_body
111
+ req = req0.path == "/diagnostic" ? req0 : req1
112
+ body = req0.path == "/diagnostic" ? body0 : body1
113
+ expect(req.header['authorization']).to eq [ SDK_KEY ]
114
+ data = JSON.parse(body)
115
+ expect(data["kind"]).to eq "diagnostic-init"
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ # TODO: TLS tests with self-signed cert
122
+ end
123
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: launchdarkly-server-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.7.1
4
+ version: 5.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - LaunchDarkly
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-18 00:00:00.000000000 Z
11
+ date: 2020-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-dynamodb
@@ -302,6 +302,7 @@ files:
302
302
  - spec/integrations/store_wrapper_spec.rb
303
303
  - spec/launchdarkly-server-sdk_spec.rb
304
304
  - spec/launchdarkly-server-sdk_spec_autoloadtest.rb
305
+ - spec/ldclient_end_to_end_spec.rb
305
306
  - spec/ldclient_spec.rb
306
307
  - spec/newrelic_spec.rb
307
308
  - spec/polling_spec.rb
@@ -360,6 +361,7 @@ test_files:
360
361
  - spec/integrations/store_wrapper_spec.rb
361
362
  - spec/launchdarkly-server-sdk_spec.rb
362
363
  - spec/launchdarkly-server-sdk_spec_autoloadtest.rb
364
+ - spec/ldclient_end_to_end_spec.rb
363
365
  - spec/ldclient_spec.rb
364
366
  - spec/newrelic_spec.rb
365
367
  - spec/polling_spec.rb