@@ -2,8 +2,9 @@ defmodule Realtime.MetricsCleanerTest do
22 use Realtime.DataCase , async: true
33
44 alias Realtime.MetricsCleaner
5+ alias Realtime.Tenants.Connect
56
6- describe "metrics cleanup" do
7+ describe "metrics cleanup - vacant websockets " do
78 test "cleans up metrics for users that have been disconnected" do
89 :telemetry . execute (
910 [ :realtime , :connections ] ,
@@ -48,15 +49,15 @@ defmodule Realtime.MetricsCleanerTest do
4849 # Wait for clean up to run
4950 Process . sleep ( 200 )
5051
51- # Nothing changes
52+ # Nothing changes yet (threshold not reached)
5253 metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
5354
5455 assert String . contains? ( metrics , "tenant=\" occupied-tenant\" " )
5556 assert String . contains? ( metrics , "tenant=\" vacant-tenant1\" " )
5657 assert String . contains? ( metrics , "tenant=\" vacant-tenant2\" " )
5758
58- # Wait for clean up to run again
59- Process . sleep ( 2100 )
59+ # Wait for threshold to pass and cleanup to run
60+ Process . sleep ( 2200 )
6061
6162 # vacant tenant metrics are now gone
6263 metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
@@ -65,5 +66,127 @@ defmodule Realtime.MetricsCleanerTest do
6566 refute String . contains? ( metrics , "tenant=\" vacant-tenant1\" " )
6667 refute String . contains? ( metrics , "tenant=\" vacant-tenant2\" " )
6768 end
69+
70+ test "does not clean up metrics if websockets reconnect before threshold" do
71+ :telemetry . execute (
72+ [ :realtime , :connections ] ,
73+ % { connected: 1 , connected_cluster: 10 , limit: 100 } ,
74+ % { tenant: "reconnect-tenant" }
75+ )
76+
77+ pid = spawn_link ( fn -> Process . sleep ( :infinity ) end )
78+
79+ Beacon . join ( :users , "reconnect-tenant" , pid )
80+
81+ metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
82+ assert String . contains? ( metrics , "tenant=\" reconnect-tenant\" " )
83+
84+ start_supervised! (
85+ { MetricsCleaner , [ metrics_cleaner_schedule_timer_in_ms: 100 , vacant_metric_threshold_in_seconds: 1 ] }
86+ )
87+
88+ # Disconnect
89+ Beacon . leave ( :users , "reconnect-tenant" , pid )
90+ Process . sleep ( 500 )
91+
92+ # Reconnect before threshold
93+ pid2 = spawn_link ( fn -> Process . sleep ( :infinity ) end )
94+ Beacon . join ( :users , "reconnect-tenant" , pid2 )
95+
96+ # Wait for cleanup to run
97+ Process . sleep ( 2200 )
98+
99+ # Metrics should still be present
100+ metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
101+ assert String . contains? ( metrics , "tenant=\" reconnect-tenant\" " )
102+ end
103+ end
104+
105+ describe "metrics cleanup - disconnected tenants" do
106+ test "cleans up metrics for tenants that have been unregistered" do
107+ :telemetry . execute (
108+ [ :realtime , :connections ] ,
109+ % { connected: 1 , connected_cluster: 10 , limit: 100 } ,
110+ % { tenant: "connected-tenant" }
111+ )
112+
113+ :telemetry . execute (
114+ [ :realtime , :connections ] ,
115+ % { connected: 0 , connected_cluster: 20 , limit: 100 } ,
116+ % { tenant: "disconnected-tenant1" }
117+ )
118+
119+ :telemetry . execute (
120+ [ :realtime , :connections ] ,
121+ % { connected: 0 , connected_cluster: 20 , limit: 100 } ,
122+ % { tenant: "disconnected-tenant2" }
123+ )
124+
125+ metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
126+
127+ assert String . contains? ( metrics , "tenant=\" connected-tenant\" " )
128+ assert String . contains? ( metrics , "tenant=\" disconnected-tenant1\" " )
129+ assert String . contains? ( metrics , "tenant=\" disconnected-tenant2\" " )
130+
131+ start_supervised! (
132+ { MetricsCleaner , [ metrics_cleaner_schedule_timer_in_ms: 100 , vacant_metric_threshold_in_seconds: 1 ] }
133+ )
134+
135+ # Simulate tenant registration (connected)
136+ :telemetry . execute ( [ :syn , Connect , :registered ] , % { } , % { name: "connected-tenant" } )
137+
138+ # Simulate tenant unregistration (disconnected)
139+ :telemetry . execute ( [ :syn , Connect , :unregistered ] , % { } , % { name: "disconnected-tenant1" } )
140+ :telemetry . execute ( [ :syn , Connect , :unregistered ] , % { } , % { name: "disconnected-tenant2" } )
141+
142+ # Wait for clean up to run
143+ Process . sleep ( 200 )
144+
145+ # Nothing changes yet (threshold not reached)
146+ metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
147+
148+ assert String . contains? ( metrics , "tenant=\" connected-tenant\" " )
149+ assert String . contains? ( metrics , "tenant=\" disconnected-tenant1\" " )
150+ assert String . contains? ( metrics , "tenant=\" disconnected-tenant2\" " )
151+
152+ # Wait for threshold to pass and cleanup to run
153+ Process . sleep ( 2200 )
154+
155+ # disconnected tenant metrics are now gone
156+ metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
157+
158+ assert String . contains? ( metrics , "tenant=\" connected-tenant\" " )
159+ refute String . contains? ( metrics , "tenant=\" disconnected-tenant1\" " )
160+ refute String . contains? ( metrics , "tenant=\" disconnected-tenant2\" " )
161+ end
162+
163+ test "does not clean up metrics if tenant reconnects before threshold" do
164+ :telemetry . execute (
165+ [ :realtime , :connections ] ,
166+ % { connected: 1 , connected_cluster: 10 , limit: 100 } ,
167+ % { tenant: "reconnect-tenant" }
168+ )
169+
170+ metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
171+ assert String . contains? ( metrics , "tenant=\" reconnect-tenant\" " )
172+
173+ start_supervised! (
174+ { MetricsCleaner , [ metrics_cleaner_schedule_timer_in_ms: 100 , vacant_metric_threshold_in_seconds: 1 ] }
175+ )
176+
177+ # Simulate tenant unregistration
178+ :telemetry . execute ( [ :syn , Connect , :unregistered ] , % { } , % { name: "reconnect-tenant" } )
179+ Process . sleep ( 500 )
180+
181+ # Re-register before threshold
182+ :telemetry . execute ( [ :syn , Connect , :registered ] , % { } , % { name: "reconnect-tenant" } )
183+
184+ # Wait for cleanup to run
185+ Process . sleep ( 2200 )
186+
187+ # Metrics should still be present
188+ metrics = Realtime.PromEx . get_metrics ( ) |> IO . iodata_to_binary ( )
189+ assert String . contains? ( metrics , "tenant=\" reconnect-tenant\" " )
190+ end
68191 end
69192end
0 commit comments