# frozen_string_literal: true # Chiude sessioni abbandonate che altrimenti occupano slot MediaMTX e # fanno scattare warm-spare / scale-out Hetzner. # # - idle: wizard aperti e mai partiti (default 30 min) # - connecting / reconnecting: hang senza go_live (default 6 h) class CleanupExpiredSessionsJob include Sidekiq::Job def perform closed_idle = sweep_idle! closed_stale = sweep_stale_connect! Rails.logger.info( "[CleanupExpiredSessionsJob] idle_closed=#{closed_idle} stale_closed=#{closed_stale} " \ "idle_minutes=#{self.class.idle_minutes} stale_hours=#{self.class.stale_hours}" ) end def self.idle_minutes ENV.fetch("STREAM_SESSION_IDLE_MINUTES", "30").to_i end def self.stale_hours ENV.fetch("STREAM_SESSION_STALE_HOURS", "6").to_i end private def sweep_idle! cutoff = self.class.idle_minutes.minutes.ago count = 0 StreamSession.where(status: "idle").where("updated_at < ?", cutoff).find_each do |session| close!(session, reason: "idle_timeout") count += 1 end count end def sweep_stale_connect! cutoff = self.class.stale_hours.hours.ago count = 0 StreamSession.where(status: %w[connecting reconnecting]) .where("updated_at < ?", cutoff) .find_each do |session| close!(session, reason: "stale_#{session.status}") count += 1 end count end def close!(session, reason:) session.stream_events.create!( event_type: "error", metadata: { reason: reason }, occurred_at: Time.current ) Sessions::Stop.new(session).call rescue StandardError => e Rails.logger.warn( "[CleanupExpiredSessionsJob] session=#{session.id} reason=#{reason} " \ "#{e.class}: #{e.message}" ) end end