posthog-ruby 3.12.0 → 3.12.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: b8e287772525236ba5312d91e3a5e9c0f71ba079dbe90e73108dea39b1d02d73
4
- data.tar.gz: d5f52b018111579ab218dbfeb3220b55bb8b4d953273ef4f216d07455578cc82
3
+ metadata.gz: f51843606a47a924b1a6b772f02c61c90e9446c16827b3d5b28d92d7fdade73a
4
+ data.tar.gz: 4cfbb395d74bf0f9630b35fafafc6f4eedcdbce9e32a0a8825880f461b581fd9
5
5
  SHA512:
6
- metadata.gz: cc598260671fd298d28335308a66f5b4b4472e6c38cfd0697198ef61942f9bd9118897dc6c6b6d0e4e163d568094520f0ce08f40579af7c7b0549e6a83c46369
7
- data.tar.gz: 6227c32f2dd2c10f14c48953b4bc86e7ee7d4ddb0a7b04b28a8d5917e932a11c95f615d8ad21bdc1cb02ba6b01bd36a545c062cefb30b7201f32e55251a76120
6
+ metadata.gz: 9978900c0f4091624f901a72396f4b2915cc4532503d1bd3a17c7f7e27a142463f5dbbe8e40d621cb52ae95871055f720d5a1a7a5e4652f266604a7311e2dd68
7
+ data.tar.gz: a815192b4521d259e0f2b8c3adba4c1ef2ef2b30748b4ca56c38f5b4d2b3633b1d500d7b06fe1f51d7e4046d3df618c82e2f5a0ed84ed12eb2f87d94f57dc7b8
@@ -84,10 +84,13 @@ module PostHog
84
84
  opts[:host] = normalize_host_option(opts[:host])
85
85
 
86
86
  @queue = Queue.new
87
+ @queue_mutex = Mutex.new
87
88
  @api_key = opts[:api_key]
88
89
  @disabled = @api_key.nil? || @api_key.empty?
89
90
  @max_queue_size = opts[:max_queue_size] || Defaults::Queue::MAX_SIZE
90
91
  @worker_mutex = Mutex.new
92
+ @shutdown_mutex = Mutex.new
93
+ @shutdown = false
91
94
  @sync_mode = opts[:sync_mode] == true && !opts[:test_mode] && !@disabled
92
95
  @on_error = opts[:on_error] || proc { |status, error| }
93
96
  @worker = if opts[:test_mode] || @disabled
@@ -139,8 +142,9 @@ module PostHog
139
142
  )
140
143
  end
141
144
 
145
+ @distinct_id_has_sent_flag_calls_mutex = Mutex.new
142
146
  @distinct_id_has_sent_flag_calls = SizeLimitedHash.new(Defaults::MAX_HASH_SIZE) do |hash, key|
143
- hash[key] = []
147
+ hash[key] = SizeLimitedArray.new(Defaults::MAX_HASH_SIZE)
144
148
  end
145
149
 
146
150
  @before_send = opts[:before_send]
@@ -173,7 +177,7 @@ module PostHog
173
177
  #
174
178
  # @return [void]
175
179
  def clear
176
- @queue.clear
180
+ @queue_mutex.synchronize { @queue.clear }
177
181
  end
178
182
 
179
183
  # @!macro common_attrs
@@ -757,6 +761,16 @@ module PostHog
757
761
  #
758
762
  # @return [void]
759
763
  def shutdown
764
+ already_shutdown = @shutdown_mutex.synchronize do
765
+ if @shutdown
766
+ true
767
+ else
768
+ @shutdown = true
769
+ false
770
+ end
771
+ end
772
+ return if already_shutdown
773
+
760
774
  self.class._decrement_instance_count(@api_key) unless @disabled
761
775
  @feature_flags_poller&.shutdown_poller
762
776
  flush
@@ -764,6 +778,7 @@ module PostHog
764
778
  @sync_lock.synchronize { @transport&.shutdown }
765
779
  else
766
780
  @worker&.shutdown
781
+ @worker_thread&.join(1)
767
782
  end
768
783
  end
769
784
 
@@ -821,7 +836,16 @@ module PostHog
821
836
  ''
822
837
  end
823
838
  reported_key = "#{key}_#{response_repr}#{groups_repr}"
824
- return if @distinct_id_has_sent_flag_calls[distinct_id].include?(reported_key)
839
+ should_capture = @distinct_id_has_sent_flag_calls_mutex.synchronize do
840
+ sent_keys = @distinct_id_has_sent_flag_calls[distinct_id]
841
+ if sent_keys.include?(reported_key)
842
+ false
843
+ else
844
+ sent_keys << reported_key
845
+ true
846
+ end
847
+ end
848
+ return unless should_capture
825
849
 
826
850
  msg = {
827
851
  distinct_id: distinct_id,
@@ -832,7 +856,6 @@ module PostHog
832
856
  msg[:disable_geoip] = disable_geoip unless disable_geoip.nil?
833
857
 
834
858
  capture(msg)
835
- @distinct_id_has_sent_flag_calls[distinct_id] << reported_key
836
859
  end
837
860
 
838
861
  def _feature_flag_evaluations_host
@@ -921,7 +944,7 @@ module PostHog
921
944
  #
922
945
  # returns Boolean of whether the item was added to the queue.
923
946
  def enqueue(action)
924
- return false if @disabled
947
+ return false if @disabled || shutdown?
925
948
 
926
949
  action = process_before_send(action)
927
950
  return false if action.nil? || action.empty?
@@ -934,10 +957,17 @@ module PostHog
934
957
  return true
935
958
  end
936
959
 
937
- if @queue.length < @max_queue_size
938
- @queue << action
939
- ensure_worker_running
960
+ queued = @queue_mutex.synchronize do
961
+ if @queue.length < @max_queue_size
962
+ @queue << action
963
+ true
964
+ else
965
+ false
966
+ end
967
+ end
940
968
 
969
+ if queued
970
+ ensure_worker_running
941
971
  true
942
972
  else
943
973
  logger.warn(
@@ -995,6 +1025,10 @@ module PostHog
995
1025
  @worker_thread&.alive?
996
1026
  end
997
1027
 
1028
+ def shutdown?
1029
+ @shutdown_mutex.synchronize { @shutdown }
1030
+ end
1031
+
998
1032
  def add_local_person_and_group_properties(distinct_id, groups, person_properties, group_properties)
999
1033
  groups ||= {}
1000
1034
  person_properties ||= {}
@@ -1250,7 +1250,9 @@ module PostHog
1250
1250
  uri.hostname,
1251
1251
  uri.port,
1252
1252
  use_ssl: uri.scheme == 'https',
1253
- read_timeout: request_timeout
1253
+ open_timeout: request_timeout,
1254
+ read_timeout: request_timeout,
1255
+ write_timeout: request_timeout
1254
1256
  ) do |http|
1255
1257
  res = http.request(request_object)
1256
1258
  status_code = res.code.to_i
@@ -34,6 +34,8 @@ module PostHog
34
34
  batch_size = options[:batch_size] || Defaults::MessageBatch::MAX_SIZE
35
35
  @batch = MessageBatch.new(batch_size)
36
36
  @lock = Mutex.new
37
+ @shutdown_mutex = Mutex.new
38
+ @shutdown = false
37
39
  @transport = Transport.new api_host: options[:host], skip_ssl_verification: options[:skip_ssl_verification]
38
40
  end
39
41
 
@@ -41,26 +43,32 @@ module PostHog
41
43
  #
42
44
  # @return [void]
43
45
  def run
44
- until Thread.current[:should_exit]
46
+ until shutdown?
45
47
  return if @queue.empty?
46
48
 
47
49
  @lock.synchronize do
48
50
  consume_message_from_queue! until @batch.full? || @queue.empty?
49
51
  end
50
52
 
51
- unless @batch.empty?
52
- res = @transport.send @api_key, @batch
53
- @on_error.call(res.status, res.error) unless res.status == 200
53
+ begin
54
+ unless @batch.empty?
55
+ res = @transport.send @api_key, @batch
56
+ handle_error(res.status, res.error) unless res.status == 200
57
+ end
58
+ ensure
59
+ @lock.synchronize { @batch.clear }
54
60
  end
55
-
56
- @lock.synchronize { @batch.clear }
57
61
  end
58
62
  ensure
63
+ # Worker threads exit when the queue is drained and are restarted for the
64
+ # next burst of events. Close the persistent connection on each exit and
65
+ # let Transport reconnect lazily when a future worker sends another batch.
59
66
  @transport.shutdown
60
67
  end
61
68
 
62
69
  # @return [void]
63
70
  def shutdown
71
+ @shutdown_mutex.synchronize { @shutdown = true }
64
72
  @transport.shutdown
65
73
  end
66
74
 
@@ -74,10 +82,20 @@ module PostHog
74
82
 
75
83
  private
76
84
 
85
+ def shutdown?
86
+ @shutdown_mutex.synchronize { @shutdown }
87
+ end
88
+
77
89
  def consume_message_from_queue!
78
90
  @batch << @queue.pop
79
91
  rescue MessageBatch::JSONGenerationError => e
80
- @on_error.call(-1, e.to_s)
92
+ handle_error(-1, e.to_s)
93
+ end
94
+
95
+ def handle_error(status, error)
96
+ @on_error.call(status, error)
97
+ rescue StandardError => e
98
+ logger.error("Error in on_error callback: #{e.message}")
81
99
  end
82
100
  end
83
101
  end
@@ -52,6 +52,7 @@ module PostHog
52
52
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE if options[:skip_ssl_verification]
53
53
 
54
54
  @http = http
55
+ @http_mutex = Mutex.new
55
56
  end
56
57
 
57
58
  # Sends a batch of messages to the API
@@ -91,7 +92,9 @@ module PostHog
91
92
  #
92
93
  # @return [void]
93
94
  def shutdown
94
- @http.finish if @http.started?
95
+ @http_mutex.synchronize do
96
+ @http.finish if @http.started?
97
+ end
95
98
  end
96
99
 
97
100
  private
@@ -149,9 +152,11 @@ module PostHog
149
152
 
150
153
  [200, '{}']
151
154
  else
152
- @http.start unless @http.started? # Maintain a persistent connection
153
- response = @http.request(request, payload)
154
- [response.code.to_i, response.body]
155
+ @http_mutex.synchronize do
156
+ @http.start unless @http.started? # Maintain a persistent connection
157
+ response = @http.request(request, payload)
158
+ [response.code.to_i, response.body]
159
+ end
155
160
  end
156
161
  end
157
162
 
data/lib/posthog/utils.rb CHANGED
@@ -166,5 +166,24 @@ module PostHog
166
166
  super
167
167
  end
168
168
  end
169
+
170
+ # Array that drops the oldest item when it reaches a maximum length.
171
+ #
172
+ # @api private
173
+ class SizeLimitedArray < Array
174
+ # @param max_length [Integer]
175
+ def initialize(max_length)
176
+ super()
177
+ @max_length = max_length
178
+ end
179
+
180
+ # @param value [Object]
181
+ # @return [Array]
182
+ def <<(value)
183
+ shift if length >= @max_length
184
+ super
185
+ end
186
+ end
187
+ private_constant :SizeLimitedArray
169
188
  end
170
189
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PostHog
4
- VERSION = '3.12.0'
4
+ VERSION = '3.12.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.12.0
4
+ version: 3.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''