posthog-ruby 3.14.3 → 3.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78690fdd0687ca0ba5ca1580bd38be10ee4ca8af77886ba7613556f27cadc882
4
- data.tar.gz: 01cefb30c994729d2950cfc9d5701bdf29dbf8555101a0cbc7febd7be9e5a81f
3
+ metadata.gz: edb7fbf2f848ccb05f6a79f9c3429d395ac39cde5fdd1f83c59d97990231cbc8
4
+ data.tar.gz: bf96ccaccf1cf2117b502311895d95eb32de786b005809bf1d03471c67fc3920
5
5
  SHA512:
6
- metadata.gz: fbfa25966ae2e7a7275bbb11faa1fa1b1b9813dfc08540cd5e26693c765db48c3d3faa3fe1c542b044693cded6676a71465eb3ce2092428d7b4cc3c9567bf47b
7
- data.tar.gz: 458ae4437710f4f6adf0e62271cf8cf5b8788334bb35ed016dc4e1ccfdbc7434ba29c1efad5d58243aad97dffb3a8a8949a2571c97557ed4e036809d3b1e4ffe
6
+ metadata.gz: a60d451d311741d7d3407515a8b05a0029a24d098445aae51fe4c4d51ab894c4005c0f78267f4d5717681a258ef83091e62e508d8f902068a6e9321ceead274b
7
+ data.tar.gz: 01b522405e918921a9667a1cf47271b314cf55cada33687ea31d8c2ed04239f602f61adf35c891920691c25a10d0ac6ad76c816ef2160b3ccfaf6208e564baa1
@@ -33,7 +33,7 @@ module PostHog
33
33
 
34
34
  @attempts += 1
35
35
 
36
- [interval, @max_timeout_ms].min
36
+ interval.clamp(@min_timeout_ms, @max_timeout_ms)
37
37
  end
38
38
 
39
39
  private
@@ -67,6 +67,8 @@ module PostHog
67
67
  # in seconds. Defaults to 30.
68
68
  # @option opts [Integer] :feature_flag_request_timeout_seconds How long to wait for feature flag evaluation,
69
69
  # in seconds. Defaults to 3.
70
+ # @option opts [Integer] :max_retries How many times to retry batch uploads after the first send attempt.
71
+ # Defaults to the transport default. Set to 0 to disable retrying.
70
72
  # @option opts [Integer] :feature_flag_request_max_retries How many times to retry a flag request after a
71
73
  # transient network error. Each retry sleeps on the calling thread before retrying, so this adds to
72
74
  # worst-case latency. Defaults to 1. Set to 0 to disable retrying.
@@ -76,6 +78,7 @@ module PostHog
76
78
  # the same API key. Use only when you intentionally need multiple clients. Defaults to +false+.
77
79
  # @option opts [Boolean] :skip_ssl_verification +true+ to disable SSL certificate verification for requests.
78
80
  # Intended only for local development or custom deployments.
81
+ # @option opts [Boolean] :compress_request Set to +false+ to disable gzip compression for batch uploads.
79
82
  # @option opts [Object] :flag_definition_cache_provider An object implementing the {FlagDefinitionCacheProvider}
80
83
  # interface for distributed flag definition caching.
81
84
  # @option opts [Boolean] :is_server +true+ to stamp captured events with `$is_server => true` so PostHog
@@ -109,7 +112,8 @@ module PostHog
109
112
  @transport = Transport.new(
110
113
  api_host: opts[:host],
111
114
  skip_ssl_verification: opts[:skip_ssl_verification],
112
- retries: 3
115
+ retries: opts.key?(:max_retries) ? opts[:max_retries].to_i + 1 : 3,
116
+ compress_request: opts[:compress_request]
113
117
  )
114
118
  @sync_lock = Mutex.new
115
119
  end
@@ -150,7 +150,7 @@ module PostHog
150
150
  group_properties: group_properties
151
151
  }
152
152
  request_data[:flag_keys_to_evaluate] = flag_keys if flag_keys && !flag_keys.empty?
153
- request_data[:geoip_disable] = true if disable_geoip
153
+ request_data[:geoip_disable] = disable_geoip unless disable_geoip.nil?
154
154
 
155
155
  flags_response = _request_feature_flag_evaluation(request_data)
156
156
 
@@ -27,6 +27,7 @@ module PostHog
27
27
  # @option options [Proc] :on_error Callback invoked as `on_error.call(status, error)`.
28
28
  # @option options [String] :host PostHog API host URL.
29
29
  # @option options [Boolean] :skip_ssl_verification Disable SSL certificate verification.
30
+ # @option options [Boolean] :compress_request Set to +false+ to disable gzip batch request bodies.
30
31
  def initialize(queue, api_key, options = {})
31
32
  symbolize_keys! options
32
33
  @queue = queue
@@ -42,7 +43,12 @@ module PostHog
42
43
  @flush_requested = false
43
44
  @shutdown = false
44
45
  @pid = Process.pid
45
- @transport_options = { api_host: options[:host], skip_ssl_verification: options[:skip_ssl_verification] }
46
+ @transport_options = {
47
+ api_host: options[:host],
48
+ skip_ssl_verification: options[:skip_ssl_verification],
49
+ compress_request: options[:compress_request]
50
+ }
51
+ @transport_options[:retries] = options[:max_retries].to_i + 1 if options.key?(:max_retries)
46
52
  @transport = Transport.new(@transport_options)
47
53
  end
48
54
 
@@ -8,6 +8,8 @@ require 'posthog/backoff_policy'
8
8
  require 'net/http'
9
9
  require 'net/https'
10
10
  require 'json'
11
+ require 'time'
12
+ require 'zlib'
11
13
 
12
14
  module PostHog
13
15
  # HTTP transport used by the SDK workers.
@@ -28,6 +30,7 @@ module PostHog
28
30
  # @option options [Integer] :retries Number of retry attempts for retryable failures.
29
31
  # @option options [PostHog::BackoffPolicy] :backoff_policy Backoff policy used between retries.
30
32
  # @option options [Boolean] :skip_ssl_verification Disable SSL certificate verification.
33
+ # @option options [Boolean] :compress_request Whether to gzip batch request bodies. Defaults to +true+.
31
34
  def initialize(options = {})
32
35
  if options[:api_host]
33
36
  uri = URI.parse(options[:api_host])
@@ -40,10 +43,12 @@ module PostHog
40
43
  options[:port] = options[:port].nil? ? PORT : options[:port]
41
44
  options[:ssl] = options[:ssl].nil? ? SSL : options[:ssl]
42
45
 
43
- @headers = options[:headers] || HEADERS
46
+ @headers = (options[:headers] || HEADERS).dup
44
47
  @path = options[:path] || PATH
45
48
  @retries = options[:retries] || RETRIES
46
49
  @backoff_policy = options[:backoff_policy] || PostHog::BackoffPolicy.new
50
+ @compress_request = options[:compress_request] != false
51
+ @last_retry_after = nil
47
52
 
48
53
  http = Net::HTTP.new(options[:host], options[:port])
49
54
  http.use_ssl = options[:ssl]
@@ -100,10 +105,8 @@ module PostHog
100
105
  private
101
106
 
102
107
  def should_retry_request?(status_code, body)
103
- if status_code >= 500
104
- true # Server error
105
- elsif status_code == 429 # rubocop:disable Lint/DuplicateBranch
106
- true # Rate limited
108
+ if status_code >= 500 || [408, 429].include?(status_code)
109
+ true # Server error, request timeout, or rate limited
107
110
  elsif status_code >= 400
108
111
  logger.error(body)
109
112
  false # Client error. Do not retry, but log
@@ -133,33 +136,75 @@ module PostHog
133
136
 
134
137
  if should_retry && (retries_remaining > 1)
135
138
  logger.debug("Retrying request, #{retries_remaining} retries left")
136
- sleep(@backoff_policy.next_interval.to_f / 1000)
139
+ sleep(retry_delay_seconds)
137
140
  retry_with_backoff(retries_remaining - 1, &block)
138
141
  else
139
142
  [result, caught_exception]
140
143
  end
141
144
  end
142
145
 
146
+ def retry_delay_seconds
147
+ retry_after = parse_retry_after(@last_retry_after)
148
+ @last_retry_after = nil
149
+ return retry_after if retry_after
150
+
151
+ @backoff_policy.next_interval.to_f / 1000
152
+ end
153
+
154
+ def parse_retry_after(value)
155
+ return nil if value.nil? || value.empty?
156
+
157
+ seconds = Float(value, exception: false)
158
+ return seconds if seconds && seconds >= 0
159
+
160
+ parsed_time = Time.httpdate(value)
161
+ delay = parsed_time - Time.now
162
+ delay.positive? ? delay : nil
163
+ rescue ArgumentError
164
+ nil
165
+ end
166
+
143
167
  # Sends a request for the batch, returns [status_code, body]
144
168
  def send_request(api_key, batch)
169
+ @last_retry_after = nil
145
170
  payload = JSON.generate(api_key: api_key, batch: batch)
146
171
 
147
- request = Net::HTTP::Post.new(@path, @headers)
172
+ request_path, request_headers, request_payload = build_request(@path, @headers, payload)
173
+ request = Net::HTTP::Post.new(request_path, request_headers)
148
174
 
149
175
  if self.class.stub
150
- logger.debug "stubbed request to #{@path}: " \
176
+ logger.debug "stubbed request to #{request_path}: " \
151
177
  "api key = #{api_key}, batch = #{JSON.generate(batch)}"
152
178
 
153
179
  [200, '{}']
154
180
  else
155
181
  @http_mutex.synchronize do
156
182
  @http.start unless @http.started? # Maintain a persistent connection
157
- response = @http.request(request, payload)
183
+ response = @http.request(request, request_payload)
184
+ @last_retry_after = response['Retry-After']
158
185
  [response.code.to_i, response.body]
159
186
  end
160
187
  end
161
188
  end
162
189
 
190
+ def build_request(path, headers, payload)
191
+ return [path, headers, payload] unless @compress_request
192
+
193
+ compressed_payload = gzip_payload(payload)
194
+ return [path, headers, payload] unless compressed_payload
195
+
196
+ compressed_headers = headers.merge('Content-Encoding' => 'gzip')
197
+
198
+ [path, compressed_headers, compressed_payload]
199
+ end
200
+
201
+ def gzip_payload(payload)
202
+ Zlib.gzip(payload)
203
+ rescue Zlib::Error => e
204
+ logger.warn("gzip compression failed; sending uncompressed - #{e.message}")
205
+ nil
206
+ end
207
+
163
208
  class << self
164
209
  attr_writer :stub
165
210
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PostHog
4
- VERSION = '3.14.3'
4
+ VERSION = '3.15.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posthog-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.14.3
4
+ version: 3.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''