bitfab 0.30.1 → 0.32.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: 4a3e03384934c51dd57e27ac1213dca8f88b41ead5a0980c04bb10ba0ad464d8
4
- data.tar.gz: da9c5574b00bd66ba481a78e0f1e0ce4f8e9336b35a7b2e9013498b475622237
3
+ metadata.gz: 6c30821c7a2d174dacfae3c40d838cf9b37d2f71e07be3b95aa385507cd26867
4
+ data.tar.gz: f041e1f63eedc9397c55d70f635ca75d0f365c7b6a970f943b6a282bcc4b10e9
5
5
  SHA512:
6
- metadata.gz: 97f2755495103e92c94258f1763a1066bfc5a1944168e10dec1ad1e0bd24a58ca916791122cf3673f52326ca0d5b89b7ca8324071d40b6c408f3153167f6c95c
7
- data.tar.gz: 61ba2d4b92cfa2c2665753319c6acf67dda2d48a547088d1ab47b2e9006835fe869185f3861d4e378f5c8e76167009f2580f385b5f6416467a24ae5b9dce8242
6
+ metadata.gz: 8427f0d34ca1fbafcbd1d8582da7d24fba552635e23fdc9cba0a5afe1198a3f0f712c1c7c3a25b4229abc441c8fc4057bc7bb284f6e830173213d4194410d699
7
+ data.tar.gz: e4472dd0149b0a604439da779a5bae825f8313b41f2270701ab77b1ee46baf286c636d6022ce0df65cbca995525a0a53418ba4f2d839db582be7a17be41c9c15
@@ -118,7 +118,7 @@ module Bitfab
118
118
  # same org and trace function or the server rejects the replay
119
119
  def start_replay(trace_function_key, limit, trace_ids: nil, code_change_description: nil,
120
120
  code_change_files: nil, experiment_group_id: nil, name: nil, include_db_branch_lease: false, dataset_id: nil,
121
- grader_ids: nil)
121
+ grader_ids: nil, db_branch_settings: nil)
122
122
  payload = {
123
123
  "traceFunctionKey" => trace_function_key
124
124
  }
@@ -133,6 +133,7 @@ module Bitfab
133
133
  payload["includeDbBranchLease"] = true if include_db_branch_lease
134
134
  payload["datasetId"] = dataset_id unless dataset_id.nil?
135
135
  payload["graderIds"] = grader_ids unless grader_ids.nil?
136
+ payload["dbBranchSettings"] = db_branch_settings unless db_branch_settings.nil?
136
137
 
137
138
  # When DB branching is on, the server resolves a Neon preview branch per
138
139
  # item (snapshot + restore + poll), which can run several seconds each.
data/lib/bitfab/replay.rb CHANGED
@@ -204,7 +204,8 @@ module Bitfab
204
204
  experiment_group_id:,
205
205
  include_db_branch_lease:,
206
206
  dataset_id:,
207
- grader_ids:
207
+ grader_ids:,
208
+ db_branch_settings: db_branch_settings(environment)
208
209
  )
209
210
  test_run_id = replay_data["testRunId"]
210
211
  test_run_url = replay_data["testRunUrl"]
@@ -319,6 +320,32 @@ module Bitfab
319
320
  CC_MAX_FILE_BYTES = 500_000
320
321
  CC_MAX_TOTAL_BYTES = 2_000_000
321
322
 
323
+ # Convert the environment's branch options to the wire shape, or nil when
324
+ # nothing was set. Dropping the key entirely keeps the request identical to
325
+ # what older SDKs send.
326
+ #
327
+ # Keys: :min_cu and :max_cu are the branch compute's autoscaling floor and
328
+ # ceiling in Neon Compute Units (equal values pin the size, keeping items
329
+ # comparable); :warmup_sql is appended to the branch's readiness check so it
330
+ # warms the cache before the replayed function sees the lease.
331
+ def db_branch_settings(environment)
332
+ db_branch = environment&.db_branch
333
+ return nil if db_branch.nil? || db_branch.empty?
334
+
335
+ # Symbol or string keys, matching normalize_code_change_files: a hash
336
+ # assembled from JSON or YAML would otherwise be read as empty, leaving
337
+ # the branch on the mirror's defaults with no error to notice.
338
+ min_cu = db_branch[:min_cu] || db_branch["min_cu"]
339
+ max_cu = db_branch[:max_cu] || db_branch["max_cu"]
340
+ warmup_sql = db_branch[:warmup_sql] || db_branch["warmup_sql"]
341
+
342
+ settings = {}
343
+ settings["minCu"] = min_cu unless min_cu.nil?
344
+ settings["maxCu"] = max_cu unless max_cu.nil?
345
+ settings["warmupSql"] = warmup_sql unless warmup_sql.nil?
346
+ settings.empty? ? nil : settings
347
+ end
348
+
322
349
  # Auto-capture the code change to attach when the caller passed none. Lives
323
350
  # in replay() (the one call guaranteed to run on every replay) so it works no
324
351
  # matter how the replay was launched. Precedence: a BITFAB_CODE_CHANGE_PATH
@@ -599,9 +626,19 @@ module Bitfab
599
626
  # (only when include_db_branch_lease was sent). Release it in the +ensure+
600
627
  # below so any raise (span fetch, mock-tree build, or the replayed
601
628
  # method) frees the Neon resource. Items whose source trace had no
602
- # snapshot ref, or whose resolve failed server-side, arrive without a
603
- # lease (env.active? is false for those).
629
+ # snapshot ref arrive without a lease (env.active? is false), and
630
+ # replaying those against the live database is correct.
604
631
  lease = include_db_branch_lease ? server_item["dbBranchLease"] : nil
632
+ # A resolve that was ATTEMPTED and failed is different: the caller asked
633
+ # for a branch, so running their method against live data would produce a
634
+ # result that looks valid and is not. Fail the item instead, loudly.
635
+ lease_error = include_db_branch_lease ? server_item["dbBranchLeaseError"] : nil
636
+ if lease_error
637
+ raise "Replay requested a database branch for trace #{original_trace_id} but it " \
638
+ "could not be resolved (#{lease_error["code"]}): #{lease_error["message"]}. " \
639
+ "The method was not run, because replaying it against the live database would " \
640
+ "produce a result that looks valid but did not use the historical data you asked for."
641
+ end
605
642
 
606
643
  span = http_client.get_external_span(original_span_id)
607
644
  item_data = extract_span_data(span)
@@ -16,10 +16,40 @@ module Bitfab
16
16
  # context, so each in-flight replay item sees its own per-trace values even
17
17
  # when the SDK runs items across worker threads.
18
18
  #
19
+ # The constructor takes how each branch should be sized and warmed. That
20
+ # lives here rather than on the replay arguments because the settings only
21
+ # mean anything for a replay that has an environment.
22
+ #
19
23
  # Internally the resolved per-item state is a DB branch lease (the SDK <->
20
24
  # server protocol term). We expose its useful fields directly here so
21
25
  # customer code never sees the word.
22
26
  class ReplayEnvironment
27
+ # The branch settings this environment was constructed with, as a
28
+ # symbol-keyed hash, readable anywhere. Every other reader reports the
29
+ # lease the server resolved and is therefore replay-only.
30
+ attr_reader :db_branch
31
+
32
+ # @param min_cu [Numeric, nil] autoscaling floor for the branch's compute,
33
+ # in Neon Compute Units (0.25 to 56). Omit to keep the mirror project's
34
+ # own default. Raise it when the mirror is provisioned smaller than the
35
+ # database it stands in for, so replay latency reflects your code rather
36
+ # than a cold, undersized branch.
37
+ # @param max_cu [Numeric, nil] autoscaling ceiling, in Neon Compute Units.
38
+ # Equal to +min_cu+ pins the size, which keeps items comparable:
39
+ # otherwise a later item can run against an endpoint that already scaled
40
+ # up and post a better number for the same code.
41
+ # @param warmup_sql [String, nil] SQL that warms the branch's cache. The
42
+ # server appends it to the branch's readiness check, so it runs BEFORE
43
+ # your method sees the lease and its time is not charged to the replayed
44
+ # call. Invalid SQL fails the lease rather than silently leaving the
45
+ # branch cold.
46
+ def initialize(min_cu: nil, max_cu: nil, warmup_sql: nil)
47
+ @db_branch = {}
48
+ @db_branch[:min_cu] = min_cu unless min_cu.nil?
49
+ @db_branch[:max_cu] = max_cu unless max_cu.nil?
50
+ @db_branch[:warmup_sql] = warmup_sql unless warmup_sql.nil?
51
+ end
52
+
23
53
  # The per-trace branch URL for the item currently being replayed.
24
54
  # Raises if read outside a replay item.
25
55
  def database_url
@@ -44,6 +74,13 @@ module Bitfab
44
74
  require_snapshot[:read_only]
45
75
  end
46
76
 
77
+ # The branch's region, e.g. "aws-us-east-1". A compute runs in its
78
+ # project's region, so a replay runner elsewhere pays that round trip on
79
+ # every query.
80
+ def region
81
+ require_snapshot[:region]
82
+ end
83
+
47
84
  # The historical trace ID that produced the input for this replay item.
48
85
  def trace_id
49
86
  require_snapshot.fetch(:trace_id)
@@ -95,6 +132,7 @@ module Bitfab
95
132
  expires_at: lease["expiresAt"],
96
133
  provider_console_url: lease["providerConsoleUrl"],
97
134
  read_only: lease["readOnly"],
135
+ region: lease["region"],
98
136
  trace_id:
99
137
  }
100
138
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bitfab
4
- VERSION = "0.30.1"
4
+ VERSION = "0.32.0"
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.30.1
4
+ version: 0.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harvest Team