Module: Parse::LiveQuery
- Defined in:
- lib/parse/live_query.rb,
lib/parse/live_query.rb,
lib/parse/live_query/event.rb,
lib/parse/live_query/client.rb,
lib/parse/live_query/logging.rb,
lib/parse/live_query/event_queue.rb,
lib/parse/live_query/subscription.rb,
lib/parse/live_query/configuration.rb,
lib/parse/live_query/health_monitor.rb,
lib/parse/live_query/circuit_breaker.rb
Overview
LiveQuery requires an explicit opt-in before any subscription will open a network connection. This is a safety gate (operator must consciously enable the WebSocket egress surface), not a stability warning. Set the toggle once at boot:
Parse.live_query_enabled = true
LiveQuery provides real-time data subscriptions for reactive applications. It uses WebSockets to receive push notifications when data changes on the server. Stable since Parse Stack 3.0.0.
Defined Under Namespace
Modules: Logging Classes: AuthenticationError, CircuitBreaker, Client, Configuration, ConnectionError, Error, Event, EventQueue, EventQueueFullError, HealthMonitor, NotEnabledError, Subscription, SubscriptionError
Constant Summary collapse
- EVENTS =
Default LiveQuery events
%i[create update delete enter leave].freeze
Class Attribute Summary collapse
-
.default_client ⇒ Parse::LiveQuery::Client
The default LiveQuery client.
Class Method Summary collapse
-
.available? ⇒ Boolean
Check if LiveQuery is configured and available.
-
.client ⇒ Parse::LiveQuery::Client
Get or create the default LiveQuery client.
-
.config ⇒ Parse::LiveQuery::Configuration
Get the LiveQuery configuration object.
-
.configuration ⇒ Hash
deprecated
Deprecated.
Use configure block instead
-
.configure {|config| ... } ⇒ Configuration
Configure LiveQuery settings using a block.
-
.enabled? ⇒ Boolean
Check if LiveQuery feature is enabled.
-
.ensure_enabled! ⇒ Object
Ensure LiveQuery is enabled, raising an error if not.
-
.reset! ⇒ Object
Reset the default client (closes connection and clears instance).
-
.run_until_signal!(client: nil, signals: %i[INT TERM],, shutdown_timeout: 5.0, poll_interval: 0.25) {|client| ... }
Block until the process receives one of
signals(defaultINTandTERM), then gracefully shut down the supplied LiveQuery client and return.
Class Attribute Details
.default_client ⇒ Parse::LiveQuery::Client
Returns the default LiveQuery client.
121 122 123 |
# File 'lib/parse/live_query.rb', line 121 def default_client @default_client end |
Class Method Details
.available? ⇒ Boolean
Check if LiveQuery is configured and available
152 153 154 |
# File 'lib/parse/live_query.rb', line 152 def available? !!config.url end |
.client ⇒ Parse::LiveQuery::Client
Get or create the default LiveQuery client. Uses the configuration from Parse.setup if available.
139 140 141 142 |
# File 'lib/parse/live_query.rb', line 139 def client ensure_enabled! @default_client ||= Client.new end |
.config ⇒ Parse::LiveQuery::Configuration
Get the LiveQuery configuration object
158 159 160 |
# File 'lib/parse/live_query.rb', line 158 def config @config ||= Configuration.new end |
.configuration ⇒ Hash
Use configure block instead
Legacy configuration method for backward compatibility
188 189 190 191 192 193 194 195 |
# File 'lib/parse/live_query.rb', line 188 def configuration { url: config.url, application_id: config.application_id, client_key: config.client_key, master_key: config.master_key, } end |
.configure {|config| ... } ⇒ Configuration
Configure LiveQuery settings using a block
172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/parse/live_query.rb', line 172 def configure yield config if block_given? # Sync logging settings if config.logging_enabled Logging.enabled = true Logging.log_level = config.log_level Logging.logger = config.logger if config.logger end config end |
.enabled? ⇒ Boolean
Check if LiveQuery feature is enabled
125 126 127 |
# File 'lib/parse/live_query.rb', line 125 def enabled? Parse.live_query_enabled? end |
.ensure_enabled! ⇒ Object
Ensure LiveQuery is enabled, raising an error if not
131 132 133 |
# File 'lib/parse/live_query.rb', line 131 def ensure_enabled! raise NotEnabledError unless enabled? end |
.reset! ⇒ Object
Reset the default client (closes connection and clears instance)
145 146 147 148 |
# File 'lib/parse/live_query.rb', line 145 def reset! @default_client&.close @default_client = nil end |
.run_until_signal!(client: nil, signals: %i[INT TERM],, shutdown_timeout: 5.0, poll_interval: 0.25) {|client| ... }
This method returns an undefined value.
Block until the process receives one of signals (default
INT and TERM), then gracefully shut down the supplied
LiveQuery client and return. Designed for long-running
rake-task-style consumers of LiveQuery (rake livequery:tail,
rake installations:watch, etc.) where the caller's natural
idiom is "subscribe, then wait forever; on Ctrl-C, clean up."
Why a helper: Signal.trap blocks on MRI / macOS run in a
restricted context — calling client.unsubscribe /
client.close (which themselves take the client's internal
Monitor) directly from the trap raises ThreadError: can't be
called from trap context on the platforms that enforce
:signal_safe?. The safe idiom is "set a flag in the trap,
poll from the main thread, perform the shutdown there." This
method bundles that idiom so callers don't have to re-derive
it (and so they don't deploy the unsafe version and hit the
ThreadError in production).
The supplied block (if any) runs once before the wait loop, so callers can hand-off subscription setup that should not race the trap installation:
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/parse/live_query.rb', line 240 def run_until_signal!(client: nil, signals: %i[INT TERM], shutdown_timeout: 5.0, poll_interval: 0.25) ensure_enabled! unless signals.is_a?(Array) && !signals.empty? raise ArgumentError, "Parse::LiveQuery.run_until_signal!: signals must be a non-empty Array " \ "(got #{signals.inspect}). An empty list would block the poll loop forever " \ "with no trap installed." end target = client || self.client # Sentinel is a single-element queue rather than an instance # variable so the trap handler does only the absolute minimum # work (one `push`) — no mutex acquisition, no allocation # beyond what `<<` does internally. stop_signal = Queue.new installed = [] begin # Yield BEFORE installing traps (so a SIGINT during caller # setup still aborts normally) but INSIDE the begin/ensure so a # raise from the block — including Interrupt — still runs the # shutdown/restore cleanup below rather than leaking the # client's connection and threads. yield(target) if block_given? signals.each do |sig| prior = Signal.trap(sig) { stop_signal << sig } installed << [sig, prior] end # Block until a signal arrives. Use `Queue#pop` with the # poll loop so trap-context limitations don't matter — we # only ever ENQUEUE from the trap; the dequeue is here on # the main thread. loop do sig = stop_signal.pop(true) rescue nil break if sig sleep poll_interval end ensure # Restore the prior trap handlers so re-running the helper # (e.g. in tests, or in a parent process that traps INT # itself) does not leak our handler. installed.each { |sig, prior| Signal.trap(sig, prior) if prior } # Shutdown from the main thread, not the trap context. target.shutdown(timeout: shutdown_timeout) if target.respond_to?(:shutdown) end end |