railwatch 0.3.2 → 0.3.4
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 +32 -0
- data/app/channels/railwatch/environment_channel.rb +22 -1
- data/app/models/railwatch/environment.rb +17 -3
- data/lib/generators/railwatch/install/install_generator.rb +15 -1
- data/lib/railwatch/embedded.rb +0 -4
- data/lib/railwatch/version.rb +1 -1
- 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: 3d212beaade3dc390933ea8a41bd49eb1bbf2c896056071516aac8242b39eb07
|
|
4
|
+
data.tar.gz: e647976f9634c1e0ba390f6dec52866d190401728363e3dcd1fa93aa2976af3d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c669c17f558dec72be16f175b06abc5769680591349c2169f6598fc26575191558bd00b903ead0f1f4287bab718c5097b0550ff60e7cfe5fe82fa53940c7a953
|
|
7
|
+
data.tar.gz: fc9a32a877b22e12e22b7738b4b479c2aa8b9d1dcc5c97f7ed003f5b421ea3e1a95f917221c195c9b01a487ac124d413dc561a22f96e7483e4891bb5db95b685
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.4 (2026-09-20)
|
|
4
|
+
|
|
5
|
+
- Fix the embedded dashboard offering its install steps to an install that is
|
|
6
|
+
already reporting. `last_seen_at` was process-local state, set by whichever
|
|
7
|
+
process ingested a batch. A deployed embedded install ingests in the writer
|
|
8
|
+
process the Puma plugin forks and renders the dashboard in a web one, so the
|
|
9
|
+
web process never saw it set and read the nil as "no events yet" -- add the
|
|
10
|
+
gem, run the generator, set the token, run the doctor -- no matter how much
|
|
11
|
+
had been recorded. It now reads the newest batch row from the telemetry
|
|
12
|
+
database, which every process shares.
|
|
13
|
+
- Fix live updates never connecting. The channel asked for
|
|
14
|
+
`connection.request`, which Action Cable defines below `private` for use
|
|
15
|
+
inside a Connection subclass; from a channel it raises NoMethodError, so
|
|
16
|
+
every subscribe failed and the dashboard sat on "Disconnected" while the
|
|
17
|
+
client retried. It now builds the request from the connection's public `env`.
|
|
18
|
+
- Add the gem's first channel spec, with a connection stub that mirrors
|
|
19
|
+
ActionCable::Connection::Base's real method visibility. Action Cable's own
|
|
20
|
+
ConnectionStub defines neither `request` nor `env`, so a stub that exposed a
|
|
21
|
+
public `request` would have agreed with the broken code.
|
|
22
|
+
|
|
23
|
+
## 0.3.3 (2026-09-19)
|
|
24
|
+
|
|
25
|
+
- Fix `railwatch:install --local` writing test databases that parallel test
|
|
26
|
+
runners cannot share. The generated `test` entries named
|
|
27
|
+
`storage/test_railwatch*.sqlite3` with no `TEST_ENV_NUMBER`, so every worker
|
|
28
|
+
in a parallel run opened the same two SQLite files and raced through them:
|
|
29
|
+
`ActiveRecord::PendingMigrationError` and `SQLite3::IOException: disk I/O
|
|
30
|
+
error` out of `configure_connection`, on every shard. Rails' own test
|
|
31
|
+
database naming carries the number for this reason, and the generated names
|
|
32
|
+
now do too. An app with no parallel runner sets no `TEST_ENV_NUMBER`, so its
|
|
33
|
+
generated file is unchanged and no existing install needs migrating.
|
|
34
|
+
|
|
3
35
|
## 0.3.2 (2026-09-19)
|
|
4
36
|
|
|
5
37
|
- Fix an embedded install's rake tasks reporting over HTTP instead of into
|
|
@@ -18,11 +18,32 @@ module Railwatch
|
|
|
18
18
|
# timestamp and per-type counts), never telemetry records.
|
|
19
19
|
class EnvironmentChannel < ActionCable::Channel::Base
|
|
20
20
|
def subscribed
|
|
21
|
-
if params[:id].to_i == Environment::ID && Railwatch.config.dashboard_channel_allowed?(
|
|
21
|
+
if params[:id].to_i == Environment::ID && Railwatch.config.dashboard_channel_allowed?(connection_request)
|
|
22
22
|
stream_from "environment_#{Environment::ID}"
|
|
23
23
|
else
|
|
24
24
|
reject
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# Built from the connection's env rather than asking it for its request:
|
|
31
|
+
# ActionCable::Connection::Base#request is private (Rails documents it for
|
|
32
|
+
# use inside a Connection subclass, not from a channel), so the obvious
|
|
33
|
+
# call raises NoMethodError, every subscribe fails, and the dashboard sits
|
|
34
|
+
# on "Disconnected" retrying forever. `env` is public and carries
|
|
35
|
+
# everything a gate reads -- the Authorization header for HTTP Basic, the
|
|
36
|
+
# cookies a dashboard_user resolver looks at.
|
|
37
|
+
#
|
|
38
|
+
# Merging env_config first is what makes those cookies readable: it is
|
|
39
|
+
# where the key generator, the secret and the cookie serializer live, so
|
|
40
|
+
# without it `cookie_jar.signed` finds nothing and a resolver that
|
|
41
|
+
# authenticates by signed cookie refuses a subscriber it should admit.
|
|
42
|
+
# Same construction Connection#request itself uses.
|
|
43
|
+
def connection_request
|
|
44
|
+
env = connection.env
|
|
45
|
+
env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
|
|
46
|
+
ActionDispatch::Request.new(env)
|
|
47
|
+
end
|
|
27
48
|
end
|
|
28
49
|
end
|
|
@@ -31,7 +31,20 @@ module Railwatch
|
|
|
31
31
|
def paused? = false
|
|
32
32
|
def token_prefix = "embedded"
|
|
33
33
|
def retention_days = 7
|
|
34
|
-
|
|
34
|
+
# Deliberately read from the telemetry database rather than held in this
|
|
35
|
+
# process. A deployed embedded install ingests in the writer process and
|
|
36
|
+
# renders the dashboard in a web one, so a value set during ingest is
|
|
37
|
+
# invisible to the page that needs it -- and a nil here is what the
|
|
38
|
+
# dashboard treats as "no events yet", so it showed its install steps no
|
|
39
|
+
# matter how much had been recorded. The newest batch row is the same
|
|
40
|
+
# fact, in the file both processes already share, one indexed lookup away.
|
|
41
|
+
# Ordered by received_at, not id: batches are written concurrently, so one
|
|
42
|
+
# that captured an earlier receipt time can land after a later one, and
|
|
43
|
+
# taking the newest row by insertion order would hand the dashboard a
|
|
44
|
+
# timestamp that goes backwards. `recent` is the scope that states this.
|
|
45
|
+
def last_seen_at
|
|
46
|
+
with_telemetry { Telemetry::IngestBatch.recent.pick(:received_at) }
|
|
47
|
+
end
|
|
35
48
|
def application = Application.current
|
|
36
49
|
def issues = Issue.where(environment_id: ID)
|
|
37
50
|
def deploys = Deploy.where(environment_id: ID)
|
|
@@ -43,8 +56,9 @@ module Railwatch
|
|
|
43
56
|
# dashboard can flag silent ones. One embedded install is its own server.
|
|
44
57
|
def expected_servers = []
|
|
45
58
|
|
|
46
|
-
# Ingest::Batch touches this
|
|
47
|
-
|
|
59
|
+
# Ingest::Batch touches this after writing a batch. Nothing to record: the
|
|
60
|
+
# batch row it just wrote is what last_seen_at reads.
|
|
61
|
+
def update_columns(last_seen_at:) = nil
|
|
48
62
|
|
|
49
63
|
# GlobalID for Active Job arguments (RollupJob.perform_later(environment, bucket)).
|
|
50
64
|
include GlobalID::Identification
|
|
@@ -383,12 +383,26 @@ module Railwatch
|
|
|
383
383
|
lines.insert(start + 1, " primary:\n")
|
|
384
384
|
stop += 1
|
|
385
385
|
end
|
|
386
|
-
entries = format(RAILWATCH_DATABASES, env: env).lines.map { |line| " #{line}" }
|
|
386
|
+
entries = format(RAILWATCH_DATABASES, env: database_prefix(env)).lines.map { |line| " #{line}" }
|
|
387
387
|
lines = insert_lines(lines, stop, entries.join).lines
|
|
388
388
|
end
|
|
389
389
|
lines.join
|
|
390
390
|
end
|
|
391
391
|
|
|
392
|
+
# What the database filenames are built from. For test that has to carry
|
|
393
|
+
# TEST_ENV_NUMBER, the way Rails' own test database naming does: runners
|
|
394
|
+
# like parallel_tests give each worker its own number and expect a
|
|
395
|
+
# database per worker. Without it every worker in a run opens the same
|
|
396
|
+
# two SQLite files and they fight over them -- observed as
|
|
397
|
+
# PendingMigrationError and "disk I/O error" from configure_connection,
|
|
398
|
+
# on an app running four workers. An app with no such runner sets no
|
|
399
|
+
# TEST_ENV_NUMBER, so the suffix is empty and the name is unchanged.
|
|
400
|
+
def self.database_prefix(env)
|
|
401
|
+
return env unless env == "test"
|
|
402
|
+
|
|
403
|
+
%(test<%= ENV["TEST_ENV_NUMBER"] %>)
|
|
404
|
+
end
|
|
405
|
+
|
|
392
406
|
# Unconditional: `bundle exec puma` evaluates this file before it loads
|
|
393
407
|
# the Rack app, so `if defined?(Railwatch)` would be false there and the
|
|
394
408
|
# writer would never start. The plugin itself is inert when Railwatch is
|
data/lib/railwatch/embedded.rb
CHANGED
data/lib/railwatch/version.rb
CHANGED