trellis-pg 0.1.0.pre.beta → 0.1.0.pre.gamma

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: 040d3074f1223a81e28989c5d0a2b7825e84806ea0b088894fc1ea0daaf68312
4
- data.tar.gz: e5bbfe7ce9446bd67d7b01666e555255a6ab39687c2c7415080789ddb8a934ac
3
+ metadata.gz: 8839af0acc8f206000a1348bbba21b4ea1d06784bf7d677c0244f0c630863c00
4
+ data.tar.gz: 77f8ffb6fc607c81fcbb614a6238aa9c21770616a525aeda1df4a007247c0d59
5
5
  SHA512:
6
- metadata.gz: 0f56d84b4f68c1619f480040e659513872e4c6d9f93358eff375b400b7e5b22eb9c2c29080c5433cc24ae9ab33cb8467f735c151e36c6634fea094fa2e04a5de
7
- data.tar.gz: cc1c7b5b6ed393b91c6ed3a866a0172ddb085b297e4c7914ec4a3de56f32163734449d68a2d28e40192bc147c3b797cc16222ff4e7d2b943fbb97a84ac498847
6
+ metadata.gz: fc0f00f2deb17dcbb647ca2ff60d0da513e77987fc9d4206cf1c4f723412284d44f337120dc1c667a7d6149a07f144d97825a6f9cf473d2f1c3f18630e5c1e00
7
+ data.tar.gz: 8c00d355d02a8437815fedfa97e519c4ce2fe576e46a4614c273bd1c290c89729bc1f83e1c0176b315f5a26a1566ab74a01b5453b59f25a411308e415c93674e
data/README.md CHANGED
@@ -103,6 +103,9 @@ Nothing in the binding uses it.
103
103
  and `self_check_job` returns `nil` for the replaced job or one whose
104
104
  transform was dropped. With no drain worker anywhere in the fleet a job
105
105
  stays `:queued`.
106
+ - `Trellis::Metrics.render_prometheus`: the process-wide metrics registry as
107
+ Prometheus text, for a `/metrics` route the app already serves (the
108
+ binding opens no port; see [Metrics](#metrics)). It needs no handle.
106
109
 
107
110
  ```ruby
108
111
  require "trellis/pg"
@@ -172,6 +175,32 @@ Every handle (each `Trellis::Instance` too) costs this again. The full
172
175
  accounting is in
173
176
  [`docs/embedding.md`](../../docs/embedding.md#what-a-handle-uses).
174
177
 
178
+ ### Metrics
179
+
180
+ The engine's metrics live in one registry per process, holding the series of
181
+ every handle in it; `Trellis::Metrics.render_prometheus` renders them in
182
+ Prometheus's text format. Every series carries a `trellis_instance` label
183
+ (`<database>/<catalog schema>`), so instances in one process stay apart, and
184
+ `trellis_instance_up` is 1 while an instance's handle runs and 0 after it
185
+ shuts down. The metrics themselves are listed in
186
+ [`docs/observability.md`](../../docs/observability.md).
187
+
188
+ The binding opens no port, so serve the text from a route of the app's own:
189
+
190
+ ```ruby
191
+ # config/routes.rb
192
+ get "/metrics", to: proc {
193
+ [200, { "content-type" => "text/plain; version=0.0.4" }, [Trellis::Metrics.render_prometheus]]
194
+ }
195
+ ```
196
+
197
+ Under a forking server each worker process has its own registry, holding
198
+ only its own handles' series, so Prometheus scrapes each worker (or the
199
+ worker handle, `staging: true`, runs in a process of its own that it
200
+ scrapes). A process forked while its parent had a handle running can't
201
+ render the registry, as it can't connect: it raises
202
+ `Trellis::ForkedHandleError` (see [Forking servers](#forking-servers)).
203
+
175
204
  ### Several instances
176
205
 
177
206
  A process can hold several Trellis instances, for different catalog schemas
@@ -524,6 +553,7 @@ source rows; a test database has none, so that is immediate. Runtime state
524
553
  ## Layout
525
554
 
526
555
  - `lib/`: the `Trellis` module and `Trellis::Instance`, its error classes and its `Data` values,
556
+ `Trellis::Metrics`,
527
557
  the Rails integration (`trellis/railtie.rb`, `trellis/migration.rb`),
528
558
  loaded only in an app that has Rails, and the test helpers
529
559
  (`trellis/test_support.rb`), loaded only when required.
@@ -1729,8 +1729,8 @@ dependencies = [
1729
1729
 
1730
1730
  [[package]]
1731
1731
  name = "trellis"
1732
- version = "0.1.0-beta"
1733
- source = "git+https://github.com/salesforce-misc/trellis?rev=1820fd7db091e540990d1efe190a687fb4dfeb59#1820fd7db091e540990d1efe190a687fb4dfeb59"
1732
+ version = "0.1.0-gamma"
1733
+ source = "git+https://github.com/salesforce-misc/trellis?rev=c271ef149159d9309174ca476d792c89128bce99#c271ef149159d9309174ca476d792c89128bce99"
1734
1734
  dependencies = [
1735
1735
  "deadpool",
1736
1736
  "deadpool-postgres",
@@ -1752,8 +1752,8 @@ dependencies = [
1752
1752
 
1753
1753
  [[package]]
1754
1754
  name = "trellis-embed"
1755
- version = "0.1.0-beta"
1756
- source = "git+https://github.com/salesforce-misc/trellis?rev=1820fd7db091e540990d1efe190a687fb4dfeb59#1820fd7db091e540990d1efe190a687fb4dfeb59"
1755
+ version = "0.1.0-gamma"
1756
+ source = "git+https://github.com/salesforce-misc/trellis?rev=c271ef149159d9309174ca476d792c89128bce99#c271ef149159d9309174ca476d792c89128bce99"
1757
1757
  dependencies = [
1758
1758
  "tracing",
1759
1759
  "trellis",
@@ -1761,7 +1761,7 @@ dependencies = [
1761
1761
 
1762
1762
  [[package]]
1763
1763
  name = "trellis_ruby"
1764
- version = "0.1.0-beta"
1764
+ version = "0.1.0-gamma"
1765
1765
  dependencies = [
1766
1766
  "magnus",
1767
1767
  "rb-sys",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "trellis_ruby"
3
- version = "0.1.0-beta"
3
+ version = "0.1.0-gamma"
4
4
  edition = "2024"
5
5
  publish = false
6
6
 
@@ -28,8 +28,8 @@ doctest = false
28
28
  ruby = ["dep:magnus", "dep:rb-sys"]
29
29
 
30
30
  [dependencies]
31
- trellis = { git = "https://github.com/salesforce-misc/trellis", rev = "1820fd7db091e540990d1efe190a687fb4dfeb59" }
32
- trellis-embed = { git = "https://github.com/salesforce-misc/trellis", rev = "1820fd7db091e540990d1efe190a687fb4dfeb59" }
31
+ trellis = { git = "https://github.com/salesforce-misc/trellis", rev = "c271ef149159d9309174ca476d792c89128bce99" }
32
+ trellis-embed = { git = "https://github.com/salesforce-misc/trellis", rev = "c271ef149159d9309174ca476d792c89128bce99" }
33
33
  magnus = { version = "0.9", optional = true, default-features = false, features = ["rb-sys"] }
34
34
  rb-sys = { version = "0.9", optional = true }
35
35
 
@@ -1231,6 +1231,20 @@ fn statement_kinds() -> Vec<&'static str> {
1231
1231
  .collect()
1232
1232
  }
1233
1233
 
1234
+ /// The process-wide metrics registry in Prometheus text exposition format:
1235
+ /// `trellis::Metrics::render_prometheus`, the series of every handle in this
1236
+ /// process. It needs no handle.
1237
+ ///
1238
+ /// The registry sits behind a lock the engine's threads take, so a process
1239
+ /// forked while its parent had an engine running may have inherited it held:
1240
+ /// rendering there raises `Trellis::ForkedHandleError`, as [`connect`] does,
1241
+ /// rather than risk the hang. Rendering is a short walk of the registry,
1242
+ /// so it keeps the GVL.
1243
+ fn render_prometheus(ruby: &Ruby) -> Result<String, Error> {
1244
+ engine::check().map_err(|err| forked_handle_error(ruby, forked_while_running(&err)))?;
1245
+ Ok(trellis::Metrics::new().render_prometheus())
1246
+ }
1247
+
1234
1248
  #[magnus::init]
1235
1249
  fn init(ruby: &Ruby) -> Result<(), Error> {
1236
1250
  // Interns every symbol a result can carry up front, from the closed
@@ -1252,6 +1266,7 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
1252
1266
  native.define_module_function("capture_failure_kinds", function!(capture_failure_kinds, 0))?;
1253
1267
  native.define_module_function("index_roles", function!(index_roles, 0))?;
1254
1268
  native.define_module_function("statement_kinds", function!(statement_kinds, 0))?;
1269
+ native.define_module_function("render_prometheus", function!(render_prometheus, 0))?;
1255
1270
 
1256
1271
  let handle = native.define_class("Handle", ruby.class_object())?;
1257
1272
  handle.define_method("owner_pid", method!(Handle::owner_pid, 0))?;
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trellis
4
+ # The engine's metrics, in Prometheus text exposition format: the Rust
5
+ # crate's trellis::Metrics#render_prometheus
6
+ # (docs/decisions/0009-observability-decisions.md).
7
+ #
8
+ # The registry is process-wide: one body holds the series of every Trellis
9
+ # handle in this process, so it needs no handle and works before
10
+ # Trellis.connect and after Trellis.shutdown. Every series carries a
11
+ # trellis_instance="<database>/<catalog schema>" label, so instances in one
12
+ # process stay apart. trellis_instance_up is 1 while an instance has a
13
+ # running handle and 0 after its last one shuts down; the other gauges of a
14
+ # stopped instance disappear after 60 seconds. See docs/observability.md.
15
+ #
16
+ # The binding opens no port. Serve the text from a route the app already
17
+ # has, for example in Rails:
18
+ #
19
+ # # config/routes.rb
20
+ # get "/metrics", to: proc {
21
+ # [200, { "content-type" => "text/plain; version=0.0.4" }, [Trellis::Metrics.render_prometheus]]
22
+ # }
23
+ #
24
+ # In a forking server each worker process has its own registry, holding
25
+ # only its own handles' series, so scrape every worker (or run the worker
26
+ # handle, staging: true, in a process of its own and scrape that).
27
+ #
28
+ # A process forked while its parent had an engine running may have
29
+ # inherited the registry's lock held, so rendering there raises
30
+ # Trellis::ForkedHandleError, as Trellis.connect does.
31
+ module Metrics
32
+ # Renders the registry's current contents: # HELP and # TYPE lines, then
33
+ # each series' samples.
34
+ def self.render_prometheus
35
+ Native.render_prometheus
36
+ end
37
+ end
38
+ end
data/lib/trellis/pg.rb CHANGED
@@ -24,6 +24,7 @@ else
24
24
  end
25
25
 
26
26
  require_relative "instance"
27
+ require_relative "metrics"
27
28
 
28
29
  # Embedded Trellis for Ruby apps: a native extension over the `trellis`
29
30
  # crate's BlockingTrellis, so a Rails app can define and run streaming
@@ -48,6 +49,7 @@ require_relative "instance"
48
49
  # - Operations: request_backfill, detect_capture_disruptions, has_live_drain_workers?,
49
50
  # has_live_staging_worker?, watermark_token, await_converged, self_check,
50
51
  # self_check_job.
52
+ # - Metrics: Trellis::Metrics.render_prometheus, which needs no handle.
51
53
  #
52
54
  # # A deploy's migration step: the defaults run nothing in the background.
53
55
  # Trellis.connect(url: "host=localhost dbname=app")
@@ -3,5 +3,5 @@
3
3
  module Trellis
4
4
  # The trellis-pg gem's version: the Trellis release's, which a
5
5
  # `v<VERSION>` tag releases (docs/releasing.md).
6
- VERSION = "0.1.0-beta"
6
+ VERSION = "0.1.0-gamma"
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trellis-pg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.beta
4
+ version: 0.1.0.pre.gamma
5
5
  platform: ruby
6
6
  authors:
7
7
  - Salesforce
@@ -41,6 +41,7 @@ files:
41
41
  - ext/trellis_ruby/src/lib.rs
42
42
  - lib/trellis/error.rb
43
43
  - lib/trellis/instance.rb
44
+ - lib/trellis/metrics.rb
44
45
  - lib/trellis/migration.rb
45
46
  - lib/trellis/pg.rb
46
47
  - lib/trellis/railtie.rb