From 17ff311749d5e39ba6e5fb8646a78ccfcc1c35fc Mon Sep 17 00:00:00 2001 From: Matthew Keeler Date: Thu, 30 Apr 2026 11:04:00 -0400 Subject: [PATCH] fix: parse FDv2 goodbye events with only a reason field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FDv2 goodbye event spec defines only a reason field, but the Goodbye class required silent and catastrophe — causing from_h to raise ArgumentError on spec-compliant payloads. Drop the extra fields and simplify the streaming handler to log the reason unconditionally. --- .../impl/data_system/protocolv2.rb | 20 +++---------------- lib/ldclient-rb/impl/data_system/streaming.rb | 4 +--- .../streaming_synchronizer_spec.rb | 4 +--- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/lib/ldclient-rb/impl/data_system/protocolv2.rb b/lib/ldclient-rb/impl/data_system/protocolv2.rb index e8819fbd..05d832da 100644 --- a/lib/ldclient-rb/impl/data_system/protocolv2.rb +++ b/lib/ldclient-rb/impl/data_system/protocolv2.rb @@ -160,21 +160,11 @@ class Goodbye # @return [String] The reason for goodbye attr_reader :reason - # @return [Boolean] Whether the goodbye is silent - attr_reader :silent - - # @return [Boolean] Whether this represents a catastrophic failure - attr_reader :catastrophe - # # @param reason [String] The reason for goodbye - # @param silent [Boolean] Whether the goodbye is silent - # @param catastrophe [Boolean] Whether this represents a catastrophic failure # - def initialize(reason:, silent:, catastrophe:) + def initialize(reason:) @reason = reason - @silent = silent - @catastrophe = catastrophe end # @@ -185,8 +175,6 @@ def initialize(reason:, silent:, catastrophe:) def to_h { reason: @reason, - silent: @silent, - catastrophe: @catastrophe, } end @@ -199,12 +187,10 @@ def to_h # def self.from_h(data) reason = data[:reason] - silent = data[:silent] - catastrophe = data[:catastrophe] - raise ArgumentError, "Missing required fields in Goodbye" if reason.nil? || silent.nil? || catastrophe.nil? + raise ArgumentError, "Missing required fields in Goodbye" if reason.nil? - new(reason: reason, silent: silent, catastrophe: catastrophe) + new(reason: reason) end end diff --git a/lib/ldclient-rb/impl/data_system/streaming.rb b/lib/ldclient-rb/impl/data_system/streaming.rb index 05a39e47..b7f61366 100644 --- a/lib/ldclient-rb/impl/data_system/streaming.rb +++ b/lib/ldclient-rb/impl/data_system/streaming.rb @@ -231,9 +231,7 @@ def stop when LaunchDarkly::Interfaces::DataSystem::EventName::GOODBYE goodbye = LaunchDarkly::Impl::DataSystem::ProtocolV2::Goodbye.from_h(JSON.parse(message.data, symbolize_names: true)) - unless goodbye.silent - @logger.error { "[LDClient] SSE server received error: #{goodbye.reason} (catastrophe: #{goodbye.catastrophe})" } - end + @logger.info { "[LDClient] SSE server received goodbye: #{goodbye.reason}" } nil when LaunchDarkly::Interfaces::DataSystem::EventName::ERROR diff --git a/spec/impl/data_system/streaming_synchronizer_spec.rb b/spec/impl/data_system/streaming_synchronizer_spec.rb index 11351e76..8ac45e32 100644 --- a/spec/impl/data_system/streaming_synchronizer_spec.rb +++ b/spec/impl/data_system/streaming_synchronizer_spec.rb @@ -224,9 +224,7 @@ def initialize(type, data = nil) ) ) goodbye = LaunchDarkly::Impl::DataSystem::ProtocolV2::Goodbye.new( - reason: "test reason", - silent: true, - catastrophe: false + reason: "test reason" ) selector = LaunchDarkly::Interfaces::DataSystem::Selector.new(state: "p:SOMETHING:300", version: 300)