Skip to content

Commit 19be30e

Browse files
committed
Create realtime client
1 parent d467610 commit 19be30e

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# frozen_string_literal: true
2+
3+
require 'logger'
4+
require 'faraday'
5+
require 'json'
6+
7+
module Flagsmith
8+
# Ruby client for realtime access to flagsmith.com
9+
class RealtimeClient
10+
attr_accessor :running
11+
12+
def initialize(config)
13+
@config = config
14+
@thread = nil
15+
@running = false
16+
@main = nil
17+
end
18+
19+
def endpoint
20+
"#{@config.realtime_api_url}sse/environments/#{@main.environment.api_key}/stream"
21+
end
22+
23+
def listen(main, remaining_attempts: Float::INFINITY, retry_interval: 0.5) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength
24+
last_updated_at = 0
25+
@main = main
26+
@running = true
27+
@thread = Thread.new do
28+
while @running && remaining_attempts.positive?
29+
remaining_attempts -= 1
30+
@config.logger.warn 'Beginning to pull down realtime endpoint'
31+
begin
32+
sleep retry_interval
33+
# Open connection to SSE endpoint
34+
Faraday.new(url: endpoint).get do |req|
35+
req.options.timeout = nil # Keep connection alive indefinitely
36+
req.options.open_timeout = 10
37+
end.body.each_line do |line| # rubocop:disable Style/MultilineBlockChain
38+
# SSE protocol: Skip non-event lines
39+
next if line.strip.empty? || line.start_with?(':')
40+
41+
# Parse SSE fields
42+
next unless line.start_with?('data: ')
43+
44+
data = JSON.parse(line[6..].strip)
45+
updated_at = data['updated_at']
46+
next unless updated_at > last_updated_at
47+
48+
@config.logger.info "Realtime updating environment from #{last_updated_at} to #{updated_at}"
49+
@main.update_environment
50+
last_updated_at = updated_at
51+
end
52+
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
53+
@config.logger.warn "Connection failed: #{e.message}. Retrying in #{retry_interval} seconds..."
54+
rescue StandardError => e
55+
@config.logger.error "Error: #{e.message}. Retrying in #{retry_interval} seconds..."
56+
end
57+
end
58+
end
59+
60+
@running = false
61+
end
62+
end
63+
end

0 commit comments

Comments
 (0)