standard_ledger 0.6.0 → 0.7.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 +4 -4
- data/CHANGELOG.md +45 -0
- data/README.md +11 -4
- data/lib/standard_ledger/matview.rb +14 -13
- data/lib/standard_ledger/version.rb +1 -1
- data/lib/standard_ledger.rb +27 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ddedb70c2937f7108178cce27f7150b58c39c5aadfdab2561947b626bd345d9c
|
|
4
|
+
data.tar.gz: be910d616703d17691bdc6f184247b5efe78bc959006c24f43ee4bfbeb5df263
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1bd764a4596fb6468f5ffa9b2d51e39a5203f6135bbdbde6cacec33091aa0e86cedaa1393392f417378a720f6e26987438c8a46fc80028204ecf0250ed3a7c49
|
|
7
|
+
data.tar.gz: 829aad11a875317df036555736281f0ca6d961045bd3a5b2dd6090592ce0aabce772583b34d7fd403c69a4f331bb11f46e6a9622ccc62f510fb0574dea8bd85a
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,51 @@ project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.7.0] - 2026-09-24
|
|
10
|
+
|
|
11
|
+
The Phase 4 release. The removals the cleanup plan scheduled for it (the
|
|
12
|
+
`scheduler` config, `PartialFailure`, and the engine's no-op initializer)
|
|
13
|
+
already shipped in 0.6.0, and 0.6.0 deprecated nothing, so this release only
|
|
14
|
+
changes how `refresh!` reports failures. It is a minor bump because hosts that
|
|
15
|
+
report refresh failures themselves should delete that code.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **`StandardLedger.refresh!` reports SQL failures through `Rails.error`.**
|
|
19
|
+
When the `REFRESH` statement raises, the gem emits `projection.failed` (as
|
|
20
|
+
before), then calls `Rails.error.report(error, handled: false,
|
|
21
|
+
severity: :error, context: { view:, concurrently: }, source:
|
|
22
|
+
"standard_ledger")`, then re-raises. It falls back to
|
|
23
|
+
`ActiveSupport.error_reporter` outside Rails. A reporter that raises is
|
|
24
|
+
ignored, so it can never mask the refresh error. Input errors raised before
|
|
25
|
+
any SQL runs are not reported (`ArgumentError`, `RefreshInsideTransaction`).
|
|
26
|
+
**No double reports:** Rails' `ErrorReporter` flags a reported exception
|
|
27
|
+
and skips it when the same object is reported again. That covers a host
|
|
28
|
+
rescue that reports and re-raises, and the executor wrapping the job.
|
|
29
|
+
- The `:auto` catalog-probe failure report (handled, `:warning`) now goes
|
|
30
|
+
through the same `StandardLedger.report_error` helper (`@api private`).
|
|
31
|
+
Its payload is unchanged.
|
|
32
|
+
|
|
33
|
+
### Upgrade notes (0.6.x → 0.7.0)
|
|
34
|
+
1. Bump to `gem "standard_ledger", "~> 0.7"`. Nothing was removed, so no code
|
|
35
|
+
change is required.
|
|
36
|
+
2. **Optional cleanup:** delete any report-and-re-raise rescue around
|
|
37
|
+
`refresh!`. Grepped `origin/main` of all consumers on 2026-09-24:
|
|
38
|
+
- luminality-web `app/jobs/refresh_admin_dashboard_metrics_job.rb:20-27`
|
|
39
|
+
(`rescue StandardError => e; Rails.error.report(e, handled: true,
|
|
40
|
+
context: { view: "admin_dashboard_metrics" }); raise`). Delete the rescue
|
|
41
|
+
and fix the header comment ("…does not report").
|
|
42
|
+
- sidekick-web `app/jobs/refresh_materialized_views_job.rb` has no rescue.
|
|
43
|
+
Its refresh failures are now reported by the gem, with view context,
|
|
44
|
+
before the job runner sees them.
|
|
45
|
+
- jumpdrive-web and fundbright-web don't call `refresh!`.
|
|
46
|
+
3. **Expect a different Sentry grouping context** for refresh failures:
|
|
47
|
+
`source: "standard_ledger"` and `context.view`. The error class and
|
|
48
|
+
backtrace are unchanged.
|
|
49
|
+
4. Sorbet apps: regenerate the gem RBI (`bin/tapioca gem standard_ledger`).
|
|
50
|
+
jumpdrive-web's `control-plane/config/initializers/standard_ledger.rb:12-13`
|
|
51
|
+
still mentions the removed `scheduler`/`default_async_*` config in a
|
|
52
|
+
comment. The comment is historical and harmless.
|
|
53
|
+
|
|
9
54
|
## [0.6.0] - 2026-09-24
|
|
10
55
|
|
|
11
56
|
A breaking release. The declarative projection engine is removed, and the gem
|
data/README.md
CHANGED
|
@@ -129,14 +129,21 @@ with `concurrently: false` can pass `concurrently: :auto` instead.
|
|
|
129
129
|
|
|
130
130
|
`refresh!` returns a success Result with
|
|
131
131
|
`projections[:refreshed] = [{ view:, concurrently: }]` (the concurrency mode
|
|
132
|
-
that was actually used). If the SQL fails, it emits `projection.failed
|
|
133
|
-
|
|
134
|
-
`
|
|
132
|
+
that was actually used). If the SQL fails, it emits `projection.failed`,
|
|
133
|
+
reports the error to `Rails.error` (`handled: false`, `severity: :error`,
|
|
134
|
+
`context: { view:, concurrently: }`, `source: "standard_ledger"`), and
|
|
135
|
+
re-raises so your job runner can retry. Since 0.7 you don't need a
|
|
136
|
+
report-and-re-raise rescue around `refresh!` in your job. An existing one is
|
|
137
|
+
harmless: Rails skips an exception object it has already reported, so the
|
|
138
|
+
failure is reported once. Input errors (an invalid view name, an unknown
|
|
139
|
+
`concurrently:`, `RefreshInsideTransaction`) are raised before any SQL runs
|
|
140
|
+
and are not reported by the gem. View names must be bare or `schema.view`
|
|
141
|
+
identifiers. Anything else raises `ArgumentError`.
|
|
135
142
|
|
|
136
143
|
## Installation
|
|
137
144
|
|
|
138
145
|
```ruby
|
|
139
|
-
gem "standard_ledger", "~> 0.
|
|
146
|
+
gem "standard_ledger", "~> 0.7"
|
|
140
147
|
```
|
|
141
148
|
|
|
142
149
|
(Don't reintroduce a `git:` reference. It makes a bare `bundle install` a
|
|
@@ -44,8 +44,15 @@ module StandardLedger
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# Issue `REFRESH MATERIALIZED VIEW [CONCURRENTLY] <view_name>` and emit
|
|
47
|
-
# `<prefix>.projection.refreshed` on success,
|
|
48
|
-
# `<prefix>.projection.failed
|
|
47
|
+
# `<prefix>.projection.refreshed` on success. On SQL failure, emit
|
|
48
|
+
# `<prefix>.projection.failed`, report the error through `Rails.error`
|
|
49
|
+
# (`handled: false`, `severity: :error`) and re-raise.
|
|
50
|
+
#
|
|
51
|
+
# Reporting before the re-raise means host jobs no longer need their
|
|
52
|
+
# own report-and-re-raise rescue. It cannot double-report: Rails'
|
|
53
|
+
# ErrorReporter flags a reported exception and skips it when the same
|
|
54
|
+
# object is reported again (by a host rescue, or by the executor that
|
|
55
|
+
# wraps the job).
|
|
49
56
|
#
|
|
50
57
|
# The view name is validated against a SQL-identifier regex at the
|
|
51
58
|
# boundary as defence in depth — a careless host could pass through a
|
|
@@ -72,6 +79,10 @@ module StandardLedger
|
|
|
72
79
|
"#{prefix}.projection.failed",
|
|
73
80
|
view: view_name.to_s, concurrently: concurrently, mode: :matview, error: e
|
|
74
81
|
)
|
|
82
|
+
StandardLedger.report_error(
|
|
83
|
+
e, handled: false, severity: :error,
|
|
84
|
+
context: { view: view_name.to_s, concurrently: concurrently }
|
|
85
|
+
)
|
|
75
86
|
raise
|
|
76
87
|
end
|
|
77
88
|
|
|
@@ -140,23 +151,13 @@ module StandardLedger
|
|
|
140
151
|
|
|
141
152
|
boolean(row["populated"]) && boolean(row["unique_index"])
|
|
142
153
|
rescue StandardError => e
|
|
143
|
-
report_error(e, view: view_name.to_s)
|
|
154
|
+
StandardLedger.report_error(e, handled: true, severity: :warning, context: { view: view_name.to_s })
|
|
144
155
|
false
|
|
145
156
|
end
|
|
146
157
|
|
|
147
158
|
def boolean(value)
|
|
148
159
|
ActiveModel::Type::Boolean.new.cast(value) == true
|
|
149
160
|
end
|
|
150
|
-
|
|
151
|
-
def report_error(error, context)
|
|
152
|
-
reporter =
|
|
153
|
-
if defined?(::Rails) && ::Rails.respond_to?(:error)
|
|
154
|
-
::Rails.error
|
|
155
|
-
elsif ActiveSupport.respond_to?(:error_reporter)
|
|
156
|
-
ActiveSupport.error_reporter
|
|
157
|
-
end
|
|
158
|
-
reporter&.report(error, handled: true, severity: :warning, context: context, source: "standard_ledger")
|
|
159
|
-
end
|
|
160
161
|
end
|
|
161
162
|
end
|
|
162
163
|
end
|
data/lib/standard_ledger.rb
CHANGED
|
@@ -92,9 +92,16 @@ module StandardLedger
|
|
|
92
92
|
|
|
93
93
|
# Refresh a host-owned materialized view. Issues
|
|
94
94
|
# `REFRESH MATERIALIZED VIEW [CONCURRENTLY] <view_name>` against the
|
|
95
|
-
# active connection and emits `<prefix>.projection.refreshed` on success
|
|
96
|
-
#
|
|
97
|
-
#
|
|
95
|
+
# active connection and emits `<prefix>.projection.refreshed` on success.
|
|
96
|
+
# When the refresh SQL raises, it emits `<prefix>.projection.failed`,
|
|
97
|
+
# reports the error through `Rails.error` (`handled: false`,
|
|
98
|
+
# `severity: :error`, `context: { view:, concurrently: }`,
|
|
99
|
+
# `source: "standard_ledger"`) and re-raises, so the host's job runner
|
|
100
|
+
# still drives its retry path. Hosts don't need their own
|
|
101
|
+
# report-and-re-raise; Rails skips an exception it has already reported,
|
|
102
|
+
# so an existing one is harmless. Argument errors and
|
|
103
|
+
# `RefreshInsideTransaction` are programming errors raised before any
|
|
104
|
+
# SQL runs; they are not reported by the gem.
|
|
98
105
|
#
|
|
99
106
|
# @example scheduled job refreshing a list of views
|
|
100
107
|
# VIEWS.each { |view| StandardLedger.refresh!(view, concurrently: :auto) }
|
|
@@ -130,6 +137,23 @@ module StandardLedger
|
|
|
130
137
|
)
|
|
131
138
|
end
|
|
132
139
|
|
|
140
|
+
# Report +error+ through `Rails.error` (or `ActiveSupport.error_reporter`
|
|
141
|
+
# outside Rails) with `source: "standard_ledger"`. A reporter failure is
|
|
142
|
+
# swallowed so it can never mask the error being reported.
|
|
143
|
+
#
|
|
144
|
+
# @api private
|
|
145
|
+
def report_error(error, handled:, severity:, context:)
|
|
146
|
+
reporter =
|
|
147
|
+
if defined?(::Rails) && ::Rails.respond_to?(:error)
|
|
148
|
+
::Rails.error
|
|
149
|
+
elsif ActiveSupport.respond_to?(:error_reporter)
|
|
150
|
+
ActiveSupport.error_reporter
|
|
151
|
+
end
|
|
152
|
+
reporter&.report(error, handled: handled, severity: severity, context: context, source: "standard_ledger")
|
|
153
|
+
rescue StandardError
|
|
154
|
+
nil
|
|
155
|
+
end
|
|
156
|
+
|
|
133
157
|
private
|
|
134
158
|
|
|
135
159
|
# Resolve the kind column name for an entry class. Falls back to `:kind`
|