Evita scale-in del nodo appena creato nello stesso reconcile.

Con IDLE_MINUTES=0 (o race stretta) lo scale-out veniva annullato subito; lo smoke AutoscalerJob Cloud su collaudo ora completa scale-out e scale-in.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-11 18:42:35 +02:00
co-authored by Cursor
parent 4c5af99efa
commit 00fde25c50
2 changed files with 61 additions and 7 deletions
@@ -91,6 +91,55 @@ RSpec.describe Streams::Autoscaler do
end
end
it "does not scale in a node provisioned in the same reconcile round" do
with_env(
"STREAM_AUTOSCALE_ENABLED" => "1",
"STREAM_AUTOSCALE_SOFT_FREE_SLOTS" => "2",
"STREAM_AUTOSCALE_WARM_SPARE" => "0",
"STREAM_AUTOSCALE_IDLE_MINUTES" => "0",
"STREAM_AUTOSCALE_KIND" => "lab",
"STREAM_AUTOSCALE_MAX_NODES" => "5",
"STREAM_CLOUD_PROVIDER" => "local_lab",
"STREAM_DNS_PROVIDER" => "lab",
"STREAM_NODE_HOME_MAX_PUBLISHERS" => "2",
"MEDIAMTX_API_URL" => "http://mtx-home:9997",
"MEDIAMTX_RTMP_URL" => "rtmp://home.example:1935",
"HLS_PUBLIC_URL" => "https://home.example/hls"
) do
home = Streams::NodeRegistry.ensure_home_from_env!
user = User.create!(email: "same@example.com", name: "S", password: "Password123", role: "coach")
club = Club.create!(name: "Same", sport: "volleyball")
team = club.teams.create!(name: "T", sport: "volleyball", slug: "same-t")
match = team.matches.create!(opponent_name: "X", scheduled_at: 1.hour.from_now)
2.times do
StreamSession.create!(match: match, user: user, platform: "matchlivetv", status: "live", stream_node: home)
end
provisioner = instance_double(Streams::NodeProvisioner)
created = nil
allow(provisioner).to receive(:provision_lab!) do
created = StreamNode.create!(
slug: "ingest-lab-new",
hostname: "new.lab",
role: "lab",
status: "ready",
provider: "local",
rtmp_base_url: "rtmp://h:1935",
hls_base_url: "https://h/hls",
api_base_url: "http://h:9997",
max_publishers: 4,
max_relays: 2
)
end
expect(provisioner).not_to receive(:decommission!)
result = described_class.reconcile!(provisioner: provisioner)
expect(result.actions).to include(:scale_out)
expect(result.actions.map(&:to_s)).not_to include("scale_in_ingest-lab-new")
expect(StreamNode.find_by(slug: "ingest-lab-new")).to be_present
end
end
it "scales in an idle overflow node when warm spare is not required" do
with_env(
"STREAM_AUTOSCALE_ENABLED" => "1",