railwatch 0.3.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c88b489c82195c106d414c397d391d8cf2e8d3e499dd67715d3db14fc4f7dae
4
- data.tar.gz: 3a2bb00def3c244d0eb9630f1eb6b3d4fddb29ea17cf34e2c8023123c92bdaf3
3
+ metadata.gz: 3d212beaade3dc390933ea8a41bd49eb1bbf2c896056071516aac8242b39eb07
4
+ data.tar.gz: e647976f9634c1e0ba390f6dec52866d190401728363e3dcd1fa93aa2976af3d
5
5
  SHA512:
6
- metadata.gz: f616d461f05f956503d2fa37d20dd238f98f1f77624665e6c352c675b9df12704b2a912e15b8bcf6d992192a86016b3ee39e8924b7b4a70d9bbe24f61d5c4845
7
- data.tar.gz: 8d372cfaed4dd585b39a8bbd6f042b9af6bada233e92dc7e0021613507e6bc0d570cc120bce4f1f5ef163c223ea8855a730781c16bc5fd34321a9cff10020607
6
+ metadata.gz: c669c17f558dec72be16f175b06abc5769680591349c2169f6598fc26575191558bd00b903ead0f1f4287bab718c5097b0550ff60e7cfe5fe82fa53940c7a953
7
+ data.tar.gz: fc9a32a877b22e12e22b7738b4b479c2aa8b9d1dcc5c97f7ed003f5b421ea3e1a95f917221c195c9b01a487ac124d413dc561a22f96e7483e4891bb5db95b685
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
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
+
3
23
  ## 0.3.3 (2026-09-19)
4
24
 
5
25
  - Fix `railwatch:install --local` writing test databases that parallel test
@@ -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?(connection.request)
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
- def last_seen_at = Railwatch::Embedded.last_seen_at
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 in embedded mode; there is no row to update.
47
- def update_columns(last_seen_at:) = Railwatch::Embedded.last_seen_at = last_seen_at
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
@@ -46,9 +46,5 @@ module Railwatch
46
46
  def quota_exhausted? = false
47
47
  def as_json(*) = { id: id, name: name, slug: slug, plan: plan }
48
48
  end
49
-
50
- class << self
51
- attr_accessor :last_seen_at
52
- end
53
49
  end
54
50
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Railwatch
4
- VERSION = "0.3.3"
4
+ VERSION = "0.3.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: railwatch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cole Robertson