Class: Parse::LiveQuery::HealthMonitor

Inherits:
Object
  • Object
show all
Defined in:
lib/parse/live_query/health_monitor.rb

Overview

Monitors WebSocket connection health via ping/pong and activity tracking.

Schedules periodic ping frames and detects stale connections when pong responses are not received within the configured timeout.

Examples:

monitor = HealthMonitor.new(client: client, ping_interval: 30.0, pong_timeout: 10.0)
monitor.start
# ... connection activity ...
monitor.stop

Constant Summary collapse

DEFAULT_PING_INTERVAL =

Default ping interval in seconds

30.0
DEFAULT_PONG_TIMEOUT =

Default pong timeout in seconds

10.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client:, ping_interval: DEFAULT_PING_INTERVAL, pong_timeout: DEFAULT_PONG_TIMEOUT) ⇒ HealthMonitor

Create a new health monitor

Parameters:

  • client (Client)

    the LiveQuery client to monitor

  • ping_interval (Float) (defaults to: DEFAULT_PING_INTERVAL)

    seconds between pings

  • pong_timeout (Float) (defaults to: DEFAULT_PONG_TIMEOUT)

    seconds to wait for pong



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/parse/live_query/health_monitor.rb', line 45

def initialize(client:, ping_interval: DEFAULT_PING_INTERVAL, pong_timeout: DEFAULT_PONG_TIMEOUT)
  @client = client
  @ping_interval = ping_interval
  @pong_timeout = pong_timeout

  @monitor = Monitor.new
  @running = false
  @ping_thread = nil
  @awaiting_pong = false

  @connection_established_at = nil
  @last_activity_at = nil
  @last_pong_at = nil
end

Instance Attribute Details

#connection_established_atTime? (readonly)

Returns when connection was established.

Returns:

  • (Time, nil)

    when connection was established



33
34
35
# File 'lib/parse/live_query/health_monitor.rb', line 33

def connection_established_at
  @connection_established_at
end

#last_activity_atTime? (readonly)

Returns last activity (any message received).

Returns:

  • (Time, nil)

    last activity (any message received)



36
37
38
# File 'lib/parse/live_query/health_monitor.rb', line 36

def last_activity_at
  @last_activity_at
end

#last_pong_atTime? (readonly)

Returns last pong received.

Returns:

  • (Time, nil)

    last pong received



39
40
41
# File 'lib/parse/live_query/health_monitor.rb', line 39

def last_pong_at
  @last_pong_at
end

#ping_intervalFloat (readonly)

Returns seconds between ping frames.

Returns:

  • (Float)

    seconds between ping frames



27
28
29
# File 'lib/parse/live_query/health_monitor.rb', line 27

def ping_interval
  @ping_interval
end

#pong_timeoutFloat (readonly)

Returns seconds to wait for pong response.

Returns:

  • (Float)

    seconds to wait for pong response



30
31
32
# File 'lib/parse/live_query/health_monitor.rb', line 30

def pong_timeout
  @pong_timeout
end

Instance Method Details

#health_infoHash

Get health information as a hash

Returns:



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/parse/live_query/health_monitor.rb', line 163

def health_info
  @monitor.synchronize do
    {
      running: @running,
      healthy: healthy?,
      stale: stale?,
      awaiting_pong: @awaiting_pong,
      connection_established_at: @connection_established_at,
      last_activity_at: @last_activity_at,
      last_pong_at: @last_pong_at,
      seconds_since_activity: seconds_since_activity,
      seconds_since_pong: seconds_since_pong,
      ping_interval: @ping_interval,
      pong_timeout: @pong_timeout,
    }
  end
end

#healthy?Boolean

Check if connection appears healthy

Returns:

  • (Boolean)


132
133
134
135
136
137
138
139
140
141
# File 'lib/parse/live_query/health_monitor.rb', line 132

def healthy?
  @monitor.synchronize do
    return false unless @running
    return true unless @last_activity_at

    # Consider unhealthy if no activity for 2x ping interval + pong timeout
    max_idle = (@ping_interval * 2) + @pong_timeout
    Time.now - @last_activity_at < max_idle
  end
end

#record_activityvoid

This method returns an undefined value.

Record that activity was received (any message)



107
108
109
110
111
# File 'lib/parse/live_query/health_monitor.rb', line 107

def record_activity
  @monitor.synchronize do
    @last_activity_at = Time.now
  end
end

#record_pongvoid

This method returns an undefined value.

Record that a pong was received



96
97
98
99
100
101
102
103
# File 'lib/parse/live_query/health_monitor.rb', line 96

def record_pong
  @monitor.synchronize do
    @last_pong_at = Time.now
    @last_activity_at = Time.now
    @awaiting_pong = false
  end
  Logging.debug("Pong received")
end

#running?Boolean

Check if monitor is running

Returns:

  • (Boolean)


115
116
117
# File 'lib/parse/live_query/health_monitor.rb', line 115

def running?
  @monitor.synchronize { @running }
end

#seconds_since_activityFloat?

Seconds since last activity

Returns:

  • (Float, nil)


145
146
147
148
149
150
# File 'lib/parse/live_query/health_monitor.rb', line 145

def seconds_since_activity
  @monitor.synchronize do
    return nil unless @last_activity_at
    Time.now - @last_activity_at
  end
end

#seconds_since_pongFloat?

Seconds since last pong

Returns:

  • (Float, nil)


154
155
156
157
158
159
# File 'lib/parse/live_query/health_monitor.rb', line 154

def seconds_since_pong
  @monitor.synchronize do
    return nil unless @last_pong_at
    Time.now - @last_pong_at
  end
end

#stale?Boolean

Check if connection is stale (no pong within timeout)

Returns:

  • (Boolean)


121
122
123
124
125
126
127
128
# File 'lib/parse/live_query/health_monitor.rb', line 121

def stale?
  @monitor.synchronize do
    return false unless @awaiting_pong
    return false unless @last_pong_at

    Time.now - @last_pong_at > (@ping_interval + @pong_timeout)
  end
end

#startvoid

This method returns an undefined value.

Start the health monitoring thread



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/parse/live_query/health_monitor.rb', line 62

def start
  @monitor.synchronize do
    return if @running

    @running = true
    @connection_established_at = Time.now
    @last_activity_at = Time.now
    @last_pong_at = Time.now
    @awaiting_pong = false

    @ping_thread = Thread.new { ping_loop }
    @ping_thread.abort_on_exception = false

    Logging.debug("Health monitor started", ping_interval: @ping_interval, pong_timeout: @pong_timeout)
  end
end

#stopvoid

This method returns an undefined value.

Stop the health monitoring thread



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/parse/live_query/health_monitor.rb', line 81

def stop
  @monitor.synchronize do
    return unless @running

    @running = false
    @ping_thread&.kill
    @ping_thread = nil
    @awaiting_pong = false

    Logging.debug("Health monitor stopped")
  end
end