posthog-ruby 3.21.0 → 3.22.0

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: 4ae3a78450df91e2e4cb88cd69a58e167cdb291dcc02f8ab446e3b0975c270eb
4
- data.tar.gz: b912b023ed02a37004cfbe22511437ee4df2a5ec63799d6d47e6f6aa9fc4f164
3
+ metadata.gz: b47ba497bca9801a2d3a530351c021a9441368b63c16cebb2e04dcfe7d0d3b21
4
+ data.tar.gz: ab1cb2e8238e5f19e3d9c33d96386c98478e357d7bdb96121d8332910f61477a
5
5
  SHA512:
6
- metadata.gz: 42b8b2587ee825e9a5446def45d11940b52a3a2203828b4506b2a4e1c28e2deefd61406df6ab33800bf1055c1475130554d6edef55a1498b478c43a30591f7b0
7
- data.tar.gz: 4eec6bdd11abbeee85720d2a68872ad366f39b5c9c28ce72fd96aaf54f3098218578ccac954e35fe01099975d6f5a2afcfe5016b4460520a6341e465f026ed99
6
+ metadata.gz: cc57a456ab1f6ecdce0508ccea5a5896e42901938e8eb8d29b2f8ec07bd1a16c069030feed87aa196a604fffd2e3d0e40999f12434dca839e3aa507f008afdb7
7
+ data.tar.gz: d4c2693b6a8c60706707599d2958cdf24c54aa21f4ee8d067fbdae1cf9624fad08c923d95e67c5a629cd69aaee420e221a1d7edc51422d644bef8e4218d60b66
@@ -143,7 +143,10 @@ module PostHog
143
143
  @max_queue_size = opts[:max_queue_size] || Defaults::Queue::MAX_SIZE
144
144
  @worker_mutex = Mutex.new
145
145
  @shutdown_mutex = Mutex.new
146
+ @shutdown_condition = ConditionVariable.new
146
147
  @shutdown = false
148
+ @shutdown_complete = false
149
+ @shutdown_result = false
147
150
  @sync_mode = opts[:sync_mode] == true && !opts[:test_mode] && !@disabled
148
151
  @on_error = opts[:on_error] || proc { |status, error| }
149
152
  @worker = if opts[:test_mode] || @disabled
@@ -209,29 +212,40 @@ module PostHog
209
212
  @deprecation_emitted_for = Concurrent::Set.new
210
213
  end
211
214
 
212
- # Synchronously waits until the worker has cleared the queue.
215
+ # When sync_mode is enabled, blocks until in-flight requests are complete
216
+ # and returns true. Timeout parameter has no effect.
213
217
  #
214
- # Use only for scripts which are not long-running, and will specifically
215
- # exit.
218
+ # Otherwise, waits until the worker has cleared the queue or timeout is hit.
219
+ # Note: The asynchronous wait polls and can be starved if another thread is
220
+ # actively continuing to enqueue new events.
216
221
  #
217
- # @return [void]
218
- def flush
222
+ # @param timeout [Numeric, nil] Maximum seconds to wait for pending events
223
+ # to be sent, or +nil+ to wait indefinitely.
224
+ # @return [Boolean] +true+ if all pending events were sent, +false+ if the
225
+ # timeout elapsed first.
226
+ def flush(timeout: nil)
219
227
  if @sync_mode
220
228
  # Wait for any in-flight sync send to complete
221
229
  @sync_lock.synchronize {} # rubocop:disable Lint/EmptyBlock
222
- return
230
+ return true
223
231
  end
224
232
 
225
233
  if @worker.is_a?(NoopWorker)
226
234
  clear
227
- return
235
+ return true
228
236
  end
229
237
 
238
+ deadline = timeout && (monotonic_time + timeout)
239
+
230
240
  while !@queue.empty? || @worker.is_requesting?
231
241
  ensure_worker_running
232
242
  @worker.request_flush
233
- sleep(0.1)
243
+ remaining = deadline && (deadline - monotonic_time)
244
+ return false if remaining && remaining <= 0
245
+
246
+ sleep(remaining ? remaining.clamp(0, 0.1) : 0.1)
234
247
  end
248
+ true
235
249
  end
236
250
 
237
251
  # Clears the queue without waiting.
@@ -862,29 +876,65 @@ module PostHog
862
876
 
863
877
  # Flush pending events and stop background resources.
864
878
  #
865
- # @return [void]
866
- def shutdown
867
- already_shutdown = @shutdown_mutex.synchronize do
879
+ # When sync_mode is not set, this method calls the flush method; see flush
880
+ # method documentation for timeout semantics. Unlike flush, this method
881
+ # stops the worker. So any events still queued after the timeout will not be
882
+ # sent. After the timeout, this method may wait up to one additional second
883
+ # for worker and transport cleanup, which may continue after it returns.
884
+ #
885
+ # @param timeout [Numeric, nil] Maximum seconds to wait for pending events
886
+ # to be sent, or +nil+ to wait indefinitely. Has no effect when sync_mode
887
+ # is true.
888
+ # @return [Boolean] +true+ if all pending events were sent, +false+ if the
889
+ # timeout elapsed first.
890
+ def shutdown(timeout: nil)
891
+ deadline = timeout && (monotonic_time + timeout)
892
+ shutdown_result = @shutdown_mutex.synchronize do
868
893
  if @shutdown
869
- true
894
+ until @shutdown_complete
895
+ # Avoid deadlocking when an in-flight send's on_error callback
896
+ # re-enters shutdown while the original caller is waiting for it.
897
+ break if Thread.current == @worker_thread || (@sync_mode && @sync_lock.owned?)
898
+
899
+ remaining = deadline && (deadline - monotonic_time)
900
+ break if remaining && remaining <= 0
901
+
902
+ @shutdown_condition.wait(@shutdown_mutex, remaining)
903
+ end
904
+ @shutdown_complete ? @shutdown_result : false
870
905
  else
871
906
  @shutdown = true
872
- false
907
+ nil
873
908
  end
874
909
  end
875
- return if already_shutdown
910
+ return shutdown_result unless shutdown_result.nil?
876
911
 
877
- self.class._decrement_instance_count(@api_key) unless @disabled
878
- @feature_flags_poller&.shutdown_poller
879
- flush
880
- if @sync_mode
881
- @sync_lock.synchronize { @transport&.shutdown }
882
- else
883
- @worker&.shutdown
884
- @worker_thread&.join(1)
885
- end
886
- @distinct_id_has_sent_flag_calls_mutex.synchronize do
887
- @distinct_id_has_sent_flag_calls.clear
912
+ flushed = false
913
+ begin
914
+ self.class._decrement_instance_count(@api_key) unless @disabled
915
+ @feature_flags_poller&.shutdown_poller
916
+ flushed =
917
+ if @sync_mode
918
+ # Waiting for @sync_lock lets any in-flight sync send finish before
919
+ # the connection is closed.
920
+ @sync_lock.synchronize { @transport&.shutdown }
921
+ true
922
+ else
923
+ drained = flush(timeout: timeout)
924
+ @worker&.shutdown
925
+ @worker_thread&.join(1)
926
+ drained
927
+ end
928
+ @distinct_id_has_sent_flag_calls_mutex.synchronize do
929
+ @distinct_id_has_sent_flag_calls.clear
930
+ end
931
+ flushed
932
+ ensure
933
+ @shutdown_mutex.synchronize do
934
+ @shutdown_result = flushed
935
+ @shutdown_complete = true
936
+ @shutdown_condition.broadcast
937
+ end
888
938
  end
889
939
  end
890
940
 
@@ -213,9 +213,5 @@ module PostHog
213
213
  rescue StandardError => e
214
214
  logger.error("Error shutting down transport: #{e.message}")
215
215
  end
216
-
217
- def monotonic_time
218
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
219
- end
220
216
  end
221
217
  end
data/lib/posthog/utils.rb CHANGED
@@ -136,6 +136,12 @@ module PostHog
136
136
  end
137
137
  end
138
138
 
139
+ # public: Current monotonic clock time in seconds, for measuring durations
140
+ #
141
+ def monotonic_time
142
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
143
+ end
144
+
139
145
  # Hash that clears itself when it reaches a maximum length.
140
146
  #
141
147
  # @api private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PostHog
4
- VERSION = '3.21.0'
4
+ VERSION = '3.22.0'
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.21.0
4
+ version: 3.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''