diff --git a/lib/ldclient-rb/events.rb b/lib/ldclient-rb/events.rb index 184facc4..bb12f6ec 100644 --- a/lib/ldclient-rb/events.rb +++ b/lib/ldclient-rb/events.rb @@ -1,6 +1,7 @@ require "concurrent" require "concurrent/atomics" require "concurrent/executors" +require "securerandom" require "thread" require "time" @@ -359,6 +360,7 @@ def run(sdk_key, config, client, payload, formatter) events_out = formatter.make_output_events(payload.events, payload.summary) res = nil body = events_out.to_json + payload_id = SecureRandom.uuid (0..1).each do |attempt| if attempt > 0 config.logger.warn { "[LDClient] Will retry posting events after 1 second" } @@ -374,6 +376,7 @@ def run(sdk_key, config, client, payload, formatter) req["Authorization"] = sdk_key req["User-Agent"] = "RubyClient/" + LaunchDarkly::VERSION req["X-LaunchDarkly-Event-Schema"] = CURRENT_SCHEMA_VERSION.to_s + req["X-LaunchDarkly-Payload-ID"] = payload_id req["Connection"] = "keep-alive" res = client.request(req) rescue StandardError => exn diff --git a/spec/events_spec.rb b/spec/events_spec.rb index 16bee286..1108a3ac 100644 --- a/spec/events_spec.rb +++ b/spec/events_spec.rb @@ -416,6 +416,29 @@ expect(hc.get_request["authorization"]).to eq "sdk_key" end + it "sends unique payload IDs" do + @ep = subject.new("sdk_key", default_config, hc) + e = { kind: "identify", user: user } + + @ep.add_event(e) + @ep.flush + @ep.wait_until_inactive + req0 = hc.get_request + + @ep.add_event(e) + @ep.flush + @ep.wait_until_inactive + req1 = hc.get_request + + id0 = req0["x-launchdarkly-payload-id"] + id1 = req1["x-launchdarkly-payload-id"] + expect(id0).not_to be_nil + expect(id0).not_to eq "" + expect(id1).not_to be nil + expect(id1).not_to eq "" + expect(id1).not_to eq id0 + end + def verify_unrecoverable_http_error(status) @ep = subject.new("sdk_key", default_config, hc) e = { kind: "identify", user: user } @@ -442,8 +465,15 @@ def verify_recoverable_http_error(status) @ep.flush @ep.wait_until_inactive - expect(hc.get_request).not_to be_nil - expect(hc.get_request).not_to be_nil + req0 = hc.get_request + expect(req0).not_to be_nil + req1 = hc.get_request + expect(req1).not_to be_nil + id0 = req0["x-launchdarkly-payload-id"] + expect(id0).not_to be_nil + expect(id0).not_to eq "" + expect(req1["x-launchdarkly-payload-id"]).to eq id0 + expect(hc.get_request).to be_nil # no 3rd request # now verify that a subsequent flush still generates a request