Chiude le sessioni idle abbandonate prima che occupino slot e scalino Hetzner.

Il sweeper ora termina le idle dopo 30 minuti (cron ogni 10), così non restano appese a tenere accesi i warm-spare.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-16 07:43:34 +02:00
co-authored by Cursor
parent 2db6541c91
commit cc9c4a1120
7 changed files with 134 additions and 7 deletions
@@ -0,0 +1,62 @@
# frozen_string_literal: true
require "rails_helper"
RSpec.describe CleanupExpiredSessionsJob do
let(:user) { User.create!(email: "idle-clean@test.it", name: "Idle", password: "Password123", role: "coach") }
let(:club) { Club.create!(name: "Club Idle", sport: "volleyball") }
let(:team) { club.teams.create!(name: "Team Idle", sport: "volleyball") }
let(:match) { team.matches.create!(opponent_name: "Opp", sport: "volleyball") }
before do
club.club_memberships.create!(user: user, role: "owner")
allow(SessionChannel).to receive(:broadcast_message)
allow(Streams::YoutubeRelay).to receive(:stop)
client = instance_double(Mediamtx::Client, delete_path: true)
allow(Mediamtx::Client).to receive(:for_session).and_return(client)
allow(Recordings::FinalizeSession).to receive(:new).and_return(
instance_double(Recordings::FinalizeSession, call: nil)
)
allow(Tournaments::CaptureStreamResult).to receive(:call)
end
def create_session(status:, updated_at:)
StreamSession.create!(
match: match,
user: user,
platform: "youtube",
status: status,
privacy_status: "unlisted"
).tap { |s| s.update_columns(updated_at: updated_at) }
end
it "chiude sessioni idle oltre STREAM_SESSION_IDLE_MINUTES (default 30)" do
stale = create_session(status: "idle", updated_at: 45.minutes.ago)
fresh = create_session(status: "idle", updated_at: 10.minutes.ago)
described_class.new.perform
expect(stale.reload.status).to eq("ended")
expect(fresh.reload.status).to eq("idle")
expect(stale.stream_events.where(event_type: "error").exists?).to eq(true)
end
it "chiude connecting/reconnecting stale oltre STREAM_SESSION_STALE_HOURS (default 6)" do
stale = create_session(status: "connecting", updated_at: 7.hours.ago)
fresh = create_session(status: "connecting", updated_at: 1.hour.ago)
described_class.new.perform
expect(stale.reload.status).to eq("ended")
expect(fresh.reload.status).to eq("connecting")
end
it "non tocca sessioni live" do
live = create_session(status: "live", updated_at: 2.hours.ago)
live.update_columns(started_at: 2.hours.ago)
described_class.new.perform
expect(live.reload.status).to eq("live")
end
end