bitfab 0.51.5 → 0.51.6

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: 6bf8a9d45207caf1c5a6ef62a0e9ad6af43e5ccd904a25c8b8cd1fefd73795b9
4
- data.tar.gz: 684d7a18b4dc4cde5df27bce58e9be1a7ed3dbd8a644638148d81746cd9e7683
3
+ metadata.gz: 208aed8da4ed9d2c748135161048c595f30507c946f3bb4086a560c55c1a2044
4
+ data.tar.gz: cfd965992d9304db89d53760c7e8ef8ea237394902aa33f5f0862a7388bf4c00
5
5
  SHA512:
6
- metadata.gz: f3ffe75284ce984a57b524746a640ad8b51a10b32d4835d35a1d692415a23cfd09a7730105825713919c519e5dc256b444ba329c4bd0783f24a07e933315cb87
7
- data.tar.gz: c9da6e278539c0fe49d5192d05624ce0e1ba0f36ce0e9e8bf23511fd336bc39a3b58427d1196fee0418a7569f2920aefa5c9f456c57d246d1d01ebabb0306b21
6
+ metadata.gz: b76db7c1e008f877c79d6ab25eaacd2733f3e61564eb2211ac77418d050634503b31a4dd43ecd80bf7ea098fa4fec1975b36ec4c4b3125badbbc0a3ef61dfbba
7
+ data.tar.gz: '07281744cb252b83655686936532d9d58297537c35938c2eea468a5359005ba9c8ae97149e3465f990d005f5a80a2890d04662add468602e4ca9ddaaacd704e4'
data/lib/bitfab/client.rb CHANGED
@@ -470,6 +470,7 @@ module Bitfab
470
470
  span_contexts = nil
471
471
  span_prompt = nil
472
472
  completed = false
473
+ @http_client.trace_completion.start(trace_id, span_id)
473
474
 
474
475
  complete = lambda do |final_result, final_error|
475
476
  # Never crash the host app due to span building/sending. Idempotent:
@@ -549,6 +550,8 @@ module Bitfab
549
550
  # Silently ignore: user's result/exception takes priority
550
551
  # Catches Exception (not just StandardError) to handle SystemStackError
551
552
  # from deeply nested serialization
553
+ ensure
554
+ @http_client.trace_completion.finish(trace_id, span_id)
552
555
  end
553
556
  end
554
557
 
@@ -9,6 +9,7 @@ require_relative "compress"
9
9
  require_relative "constants"
10
10
  require_relative "serialize"
11
11
  require_relative "transport"
12
+ require_relative "trace_completion"
12
13
  require_relative "version"
13
14
  require_relative "warn_once"
14
15
 
@@ -27,7 +28,7 @@ module Bitfab
27
28
  REPLAY_DB_BRANCH_REQUEST_TIMEOUT_SECONDS = 300
28
29
  private_constant :REPLAY_DB_BRANCH_REQUEST_TIMEOUT_SECONDS
29
30
 
30
- attr_reader :service_url
31
+ attr_reader :service_url, :trace_completion
31
32
 
32
33
  def initialize(api_key:, service_url: nil, timeout: 120)
33
34
  @api_key = api_key
@@ -38,6 +39,7 @@ module Bitfab
38
39
  # the export threads recording acks would hand each a different mutex.
39
40
  @delivery_mutex = Mutex.new
40
41
  @trace_deliveries = {}
42
+ @trace_completion = TraceCompletion.new
41
43
  @delivery_pid = Process.pid
42
44
  @carrier_seq_mutex = Mutex.new
43
45
  @carrier_seq = 0
@@ -126,6 +128,8 @@ module Bitfab
126
128
 
127
129
  # Queue an external span on this client's trace transport (fire-and-forget).
128
130
  def send_external_span(payload)
131
+ ref = carrier_ref(payload)
132
+ @trace_completion.record(ref.trace_id, ref.span_id) if ref&.span_id
129
133
  trace_transport&.submit(
130
134
  "external_span",
131
135
  payload.merge("sdkVersion" => VERSION),
@@ -287,6 +291,18 @@ module Bitfab
287
291
 
288
292
  # Queue an external trace on this client's trace transport (fire-and-forget).
289
293
  def send_external_trace(payload)
294
+ ref = carrier_ref(payload)
295
+ if payload["completed"] == true && ref
296
+ @trace_completion.close(ref.trace_id, dropped: payload["dropped"] == true) do |count|
297
+ submit_external_trace(payload.merge("expectedSpanCount" => count))
298
+ end
299
+ else
300
+ @trace_completion.open(ref.trace_id) if ref
301
+ submit_external_trace(payload)
302
+ end
303
+ end
304
+
305
+ def submit_external_trace(payload)
290
306
  trace_transport&.submit(
291
307
  "external_trace",
292
308
  payload.merge("sdkVersion" => VERSION),
@@ -296,6 +312,8 @@ module Bitfab
296
312
  (payload["completed"] == true) ? carrier_ref(payload) : nil
297
313
  )
298
314
  )
315
+ rescue => error
316
+ Bitfab.warn_once("trace-completion-submit", "trace completion could not be queued: #{error.message}")
299
317
  end
300
318
 
301
319
  # Read the replay traces the server has fully persisted so far.
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set" # standard:disable Lint/RedundantRequireStatement -- Required on Ruby 3.4.
4
+
5
+ module Bitfab
6
+ class TraceCompletion
7
+ def initialize
8
+ @pid = Process.pid
9
+ @mutex = Mutex.new
10
+ @traces = {}
11
+ @closed = {}
12
+ end
13
+
14
+ def start(trace_id, span_id)
15
+ synchronize do
16
+ next if @closed.key?(trace_id)
17
+
18
+ entry = state(trace_id)
19
+ entry[:span_ids].add(span_id)
20
+ entry[:active].add(span_id)
21
+ end
22
+ end
23
+
24
+ def open(trace_id)
25
+ synchronize { state(trace_id) unless @closed.key?(trace_id) }
26
+ end
27
+
28
+ def record(trace_id, span_id)
29
+ synchronize do
30
+ state(trace_id)[:span_ids].add(span_id) unless @closed.key?(trace_id)
31
+ end
32
+ end
33
+
34
+ def finish(trace_id, span_id)
35
+ ready = synchronize do
36
+ entry = @traces[trace_id]
37
+ next if entry.nil?
38
+
39
+ entry[:active].delete(span_id)
40
+ drain(trace_id, entry)
41
+ end
42
+ ready[0].call(ready[1]) unless ready.nil?
43
+ end
44
+
45
+ def close(trace_id, dropped: false, &complete)
46
+ ready = synchronize do
47
+ next [complete, @closed[trace_id]] if @closed.key?(trace_id)
48
+
49
+ entry = @traces[trace_id]
50
+ next if entry.nil?
51
+
52
+ entry[:complete] = complete
53
+ entry[:active].clear if dropped
54
+ drain(trace_id, entry)
55
+ end
56
+ ready[0].call(ready[1]) unless ready.nil?
57
+ end
58
+
59
+ private
60
+
61
+ def synchronize(&block)
62
+ if @pid != Process.pid
63
+ @pid = Process.pid
64
+ @mutex = Mutex.new
65
+ @traces = {}
66
+ @closed = {}
67
+ end
68
+ @mutex.synchronize(&block)
69
+ end
70
+
71
+ def state(trace_id)
72
+ @traces[trace_id] ||= {span_ids: Set.new, active: Set.new}
73
+ end
74
+
75
+ def drain(trace_id, entry)
76
+ return unless entry[:active].empty? && entry[:complete]
77
+
78
+ @traces.delete(trace_id)
79
+ count = entry[:span_ids].size
80
+ @closed[trace_id] = count
81
+ @closed.shift if @closed.size > 1024
82
+ [entry[:complete], count]
83
+ end
84
+ end
85
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bitfab
4
- VERSION = "0.51.5"
4
+ VERSION = "0.51.6"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitfab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.51.5
4
+ version: 0.51.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harvest Team
@@ -159,6 +159,7 @@ files:
159
159
  - lib/bitfab/span_context.rb
160
160
  - lib/bitfab/subtree.rb
161
161
  - lib/bitfab/timestamp.rb
162
+ - lib/bitfab/trace_completion.rb
162
163
  - lib/bitfab/traceable.rb
163
164
  - lib/bitfab/transport.rb
164
165
  - lib/bitfab/version.rb