railwatch 0.1.1 → 0.1.2

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: 27a48b972fe7616fbf46c861f8b0f1a9ffb4d99146ec2121cb05274ea3dee031
4
- data.tar.gz: 45c879afc12f731e446be6aa43f8a78b61d078a8f5a7cdc6294bd94c4dfe864e
3
+ metadata.gz: 50160a5f39e8b422581a3b6e6cf0b07eddc3565cfc17a8ba522bc49e15cd93df
4
+ data.tar.gz: 4f2e2fdac0c85df89a9d595fb33f02ebcf5c02a6f88ed81cb6dc19a163a2b90d
5
5
  SHA512:
6
- metadata.gz: 29512ddbb519a85a1334531289be33d59d4ceb3cf0a8c7ef55d3db04ab41ae884adf65b64ddecd40d1b70254ca76ed0ce0bbb38ec03eee0125dbae5a8b7730de
7
- data.tar.gz: 67d7a5573b95aa032a227a8dc10e440bfaee6681628de90d2948f074ceb15ffb9ea839968984beaaec545d0db161a266ba94e99cd2b3a0908c14c9e98969c2c7
6
+ metadata.gz: 584a8545680ad9c2d24ef05f6fcfd331a933cb87a310859a6c6e7df6c447b1d1f1d1ace62ccf11b899ae9bbcf0255d3b397562e57ba402e2410ba5790a99b144
7
+ data.tar.gz: 0fd7c798ae6d8b745e5e19ed9a894331b09eb6b15a179d9d6cda6d6bbb4c1d8a6b8bf15eefecdb24db57fd2b956b1eabba1085e0aba7fa074810aa2d5f41374c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 (2026-09-14)
4
+
5
+ - A failed job's exception is reported once. Solid Queue re-raises it out
6
+ of the worker thread, where its app executor reports the same error object
7
+ to `Rails.error` again after the `job_attempt` execution has finished; that
8
+ second report (source `application.solid_queue`, unlinked) doubled every
9
+ failed job's occurrence count. An error object now remembers that its
10
+ unhandled report has shipped, across executions.
11
+ - `require "railwatch/minitest"` includes the assertions into
12
+ `ActiveSupport::TestCase` through its load hook, so `assert_railwatch_queries`
13
+ works after the generator's one-line edit to `test/test_helper.rb` without
14
+ a manual `include`.
15
+ - Solid Queue's supervisor, dispatcher, scheduler, and forked workers report
16
+ role `worker` after Solid Queue renames the process. They were classified
17
+ `web` by every health sample taken after boot, with empty Puma thread
18
+ stats.
19
+ - Troubleshooting entries for `json` 3.0 against Rails 8.1.3.1 (`bin/jobs`
20
+ crash loop, not a Railwatch fault) and for deprecations that are counted
21
+ but never listed because the app's deprecation behavior lacks `:notify`.
22
+
3
23
  ## 0.1.1 (2026-09-14)
4
24
 
5
25
  - Token prefixes are `rw_` for an environment's ingest token and `rwp_`
data/docs/records.md CHANGED
@@ -652,7 +652,9 @@ ship. Forked workers start with an empty cache.
652
652
 
653
653
  ### `deprecation`
654
654
 
655
- `deprecation.rails`. See `lib/railwatch/subscribers/deprecations.rb`.
655
+ `deprecation.rails`. See `lib/railwatch/subscribers/deprecations.rb`. Rails
656
+ only emits that notification when `config.active_support.deprecation`
657
+ includes `:notify`; see [Troubleshooting](troubleshooting.md#deprecations-are-counted-but-never-listed).
656
658
 
657
659
  | Field | Meaning |
658
660
  |---|---|
@@ -12,12 +12,12 @@ the other.
12
12
 
13
13
  ## Decide whether Railwatch covers your workload
14
14
 
15
- Nightwatch parity and Sentry parity are different targets. Laravel
16
- Nightwatch is an application-monitoring product built around framework
17
- executions; Railwatch deliberately maps that model onto Rails. Sentry is a
18
- broader, multi-language managed platform with browser replay, native/mobile
19
- SDKs, a large integration catalog, and generic tracing. Those broader
20
- capabilities are not implied by Rails/Nightwatch parity.
15
+ Railwatch and Sentry aim at different targets. Railwatch is an
16
+ application-monitoring product built around Rails executions: a request,
17
+ job, scheduled task, command, or channel action and everything it did.
18
+ Sentry is a broader, multi-language managed platform with browser replay,
19
+ native/mobile SDKs, a large integration catalog, and generic tracing.
20
+ Railwatch does not claim those broader capabilities.
21
21
 
22
22
  | Workload or capability | Status | Boundary |
23
23
  |---|---|---|
data/docs/testing.md CHANGED
@@ -18,15 +18,12 @@ require "railwatch/rspec"
18
18
  That requires `railwatch/spec_helper`, includes `Railwatch::SpecHelper` into every
19
19
  example group, and defines the matchers below.
20
20
 
21
- Minitest: the same thing in `test/test_helper.rb`.
21
+ Minitest: the same thing in `test/test_helper.rb`. The require includes
22
+ `Railwatch::Minitest` into `ActiveSupport::TestCase` on its own.
22
23
 
23
24
  ```ruby
24
25
  require "rails/test_help"
25
26
  require "railwatch/minitest"
26
-
27
- class ActiveSupport::TestCase
28
- include Railwatch::Minitest
29
- end
30
27
  ```
31
28
 
32
29
  Railwatch must be *enabled* in the test environment or every block would look
@@ -81,6 +81,42 @@ to stderr prefixed `[railwatch]`. They never go to `Rails.logger`, so they
81
81
  can't become `log` records about themselves. `Railwatch.on_unrecoverable
82
82
  { |e| ... }` gets the same failures as a callback.
83
83
 
84
+ ## `bin/jobs` dies in a loop with `wrong number of arguments (given 2, expected 1)`
85
+
86
+ **Symptom.** Every Solid Queue process crashes at boot from
87
+ `json/common.rb` in `parse`, and Railwatch reports the same
88
+ `ArgumentError` from source `application.solid_queue` hundreds of times.
89
+ The web server still answers until it touches a session or a JSON column.
90
+
91
+ **Cause.** Not Railwatch. `json` 3.0 (September 2026) made `JSON.parse`'s
92
+ options keyword-only, and Active Support up to 8.1.3.1 still passes them
93
+ positionally ([rails/rails#58685](https://github.com/rails/rails/issues/58685)).
94
+ A fresh `rails new` resolves the newest `json`, so a new app hits this
95
+ before Railwatch is even installed.
96
+
97
+ **Fix.** Pin `json` below 3 until a Rails release includes the fix:
98
+
99
+ ```sh
100
+ bundle add json --version "< 3"
101
+ ```
102
+
103
+ ## Deprecations are counted but never listed
104
+
105
+ **Symptom.** The `deprecations` counter on an execution is non-zero, but
106
+ the Deprecations page stays empty.
107
+
108
+ **Cause.** Railwatch listens to the `deprecation.rails` notification, and
109
+ Rails only emits it when the app's deprecation behavior includes
110
+ `:notify`. The default in development is `:log` and in production
111
+ `:silence`, neither of which notifies.
112
+
113
+ **Fix.** Add `:notify` alongside whatever the environment already does:
114
+
115
+ ```ruby
116
+ # config/environments/production.rb
117
+ config.active_support.deprecation = [:silence, :notify]
118
+ ```
119
+
84
120
  ## Doubled scheduled_task records
85
121
 
86
122
  **Symptom.** Every recurring task shows twice on the Scheduled tasks
@@ -7,10 +7,9 @@ module Railwatch
7
7
  # assert_/refute_. Add to test/test_helper.rb:
8
8
  #
9
9
  # require "railwatch/minitest"
10
- # class ActiveSupport::TestCase
11
- # include Railwatch::Minitest
12
- # end
13
10
  #
11
+ # That includes the module into ActiveSupport::TestCase (through its load
12
+ # hook, so the require order against rails/test_help does not matter).
14
13
  # Includes Railwatch::SpecHelper, so `railwatch_records(:query)` is available
15
14
  # too. See docs/testing.md.
16
15
  module Minitest
@@ -41,3 +40,5 @@ module Railwatch
41
40
  end
42
41
  end
43
42
  end
43
+
44
+ ActiveSupport.on_load(:active_support_test_case) { include Railwatch::Minitest } if defined?(ActiveSupport.on_load)
@@ -87,6 +87,13 @@ module Railwatch
87
87
  def capture(error, handled:, severity:, context: {}, source: nil, fingerprint: nil)
88
88
  return unless Railwatch.enabled?
89
89
  return if ignored?(error)
90
+ # Solid Queue re-raises a failed job's error out of the worker thread,
91
+ # where its executor reports it to Rails.error a second time
92
+ # (source application.solid_queue) after the job_attempt execution
93
+ # has already finished and reported it. The execution's own
94
+ # first_exception_report? bookkeeping is gone by then, so the error
95
+ # object itself remembers that its unhandled report has shipped.
96
+ return if !handled && reported_unhandled?(error)
90
97
 
91
98
  exe = execution
92
99
  if exe&.first_exception_observation?(error, handled)
@@ -151,9 +158,22 @@ module Railwatch
151
158
  # children (Railwatch.tail_keep?).
152
159
  exe.exception_reported = true if exe
153
160
  Railwatch.record_now(:exception, group: group, **rec)
161
+ remember_reported(error)
154
162
  end
155
163
  end
156
164
 
165
+ def reported_unhandled?(error)
166
+ error.instance_variable_defined?(:@__railwatch_reported)
167
+ rescue StandardError
168
+ false
169
+ end
170
+
171
+ def remember_reported(error)
172
+ error.instance_variable_set(:@__railwatch_reported, true)
173
+ rescue StandardError
174
+ nil
175
+ end
176
+
157
177
  # The group hash `capture` would assign this error. Public so
158
178
  # Railwatch.attach can file an attachment against the same issue without
159
179
  # having to re-derive the bucketing rule (source snippets are skipped:
@@ -84,9 +84,12 @@ module Railwatch
84
84
 
85
85
  # Puma is loaded in every process of an app that bundles it, so a Solid
86
86
  # Queue worker is recognised first, by how it was started (bin/jobs or
87
- # `rake solid_queue:start`).
87
+ # `rake solid_queue:start`) or by the procline Solid Queue gives every
88
+ # process it forks ("solid-queue-worker(1.7.0): ..."), which replaces
89
+ # $PROGRAM_NAME after boot and would otherwise turn the supervisor,
90
+ # dispatcher, and scheduler into "web" on every health sample.
88
91
  def role
89
- if defined?(::SolidQueue) && ($PROGRAM_NAME.include?("jobs") || ARGV.first.to_s.start_with?("solid_queue:")) then "worker"
92
+ if defined?(::SolidQueue) && ($PROGRAM_NAME.include?("jobs") || $PROGRAM_NAME.start_with?("solid-queue-") || ARGV.first.to_s.start_with?("solid_queue:")) then "worker"
90
93
  elsif defined?(::Rails::Console) then "console"
91
94
  elsif $PROGRAM_NAME.end_with?("rake") then "command"
92
95
  elsif defined?(::Puma) then "web"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Railwatch
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: railwatch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cole Robertson
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-09-14 00:00:00.000000000 Z
10
+ date: 2026-09-15 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails