class CheckGatewayHealthJob < ApplicationJob queue_as :default def perform # Capture stale gateway details BEFORE update_all (update_all bypasses callbacks # and would change the scope, so we snapshot the rows first) stale_gateway_details = Gateway.where("last_heartbeat_at < ?", 2.minutes.ago) .where.not(status: "offline") .pluck(:id, :name, :device_id) offline_count = Gateway.where(id: stale_gateway_details.map(&:first)).update_all(status: "offline") if offline_count > 0 Rails.logger.warn("Marked #{offline_count} gateways as offline due to missing heartbeat") stale_gateway_details.each do |_id, name, device_id| Gateway.dispatch_ntfy("gateway_offline", title: "Gateway offline", message: "#{name} (#{device_id}) went offline — no heartbeat for 2+ minutes", priority: 4, tags: [ "rotating_light" ]) end end end end