From baac3a512b4e9fdaf3936a63dc7120c97f70af6c Mon Sep 17 00:00:00 2001 From: Emiliano Frascaro Date: Mon, 10 Aug 2026 12:29:23 +0200 Subject: [PATCH] Preserva drain/offline su home e genera slate offline nel cloud-init. Evita che ensure_home_from_env! annulli il drain a ogni allocate, e prepara /slates/offline.mp4 sul nodo Cloud per create_path MediaMTX. Co-authored-by: Cursor --- backend/app/services/streams/node_registry.rb | 8 +++++--- backend/spec/services/streams/node_registry_spec.rb | 10 ++++++++++ infra/stream-node/cloud-init.yaml | 6 ++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/backend/app/services/streams/node_registry.rb b/backend/app/services/streams/node_registry.rb index 92bc9b2..96705de 100644 --- a/backend/app/services/streams/node_registry.rb +++ b/backend/app/services/streams/node_registry.rb @@ -11,10 +11,9 @@ module Streams class << self def ensure_home_from_env! StreamNode.find_or_initialize_by(slug: HOME_SLUG).tap do |node| - node.assign_attributes( + attrs = { hostname: home_hostname, role: "home", - status: "ready", provider: "local", rtmp_base_url: MatchLiveTv.mediamtx_rtmp_url, hls_base_url: MatchLiveTv.hls_public_url, @@ -23,7 +22,10 @@ module Streams internal_hls_url: ENV.fetch("MEDIAMTX_HLS_URL", "http://mediamtx:8888"), max_publishers: ENV.fetch("STREAM_NODE_HOME_MAX_PUBLISHERS", "6").to_i, max_relays: ENV.fetch("STREAM_NODE_HOME_MAX_RELAYS", "6").to_i - ) + } + # Non sovrascrivere drain/offline/error (ops) a ogni allocate! + attrs[:status] = "ready" if node.new_record? || !%w[draining offline error].include?(node.status) + node.assign_attributes(attrs) node.save! end end diff --git a/backend/spec/services/streams/node_registry_spec.rb b/backend/spec/services/streams/node_registry_spec.rb index 42e804f..60df2d3 100644 --- a/backend/spec/services/streams/node_registry_spec.rb +++ b/backend/spec/services/streams/node_registry_spec.rb @@ -39,6 +39,16 @@ RSpec.describe Streams::NodeRegistry do end end + it "does not reset home drain/offline/error status on ensure" do + with_env(home_env) do + home = described_class.ensure_home_from_env! + home.update!(status: "draining") + + expect(described_class.ensure_home_from_env!.status).to eq("draining") + expect { described_class.allocate! }.to raise_error(Streams::NodeRegistry::NoCapacityError) + end + end + it "allocates the least loaded ready node" do with_env(home_env) do home = described_class.ensure_home_from_env! diff --git a/infra/stream-node/cloud-init.yaml b/infra/stream-node/cloud-init.yaml index 7be27af..80f4c56 100644 --- a/infra/stream-node/cloud-init.yaml +++ b/infra/stream-node/cloud-init.yaml @@ -48,6 +48,12 @@ write_files: done docker pull bluenviron/mediamtx:latest docker rm -f mediamtx 2>/dev/null || true + # Slate offline (alwaysAvailable) — richiesta da Mediamtx::Client#create_path + mkdir -p /slates + if [ ! -f /slates/offline.mp4 ]; then + ffmpeg -y -f lavfi -i color=c=black:s=1280x720:d=2 -f lavfi -i anullsrc=r=44100:cl=stereo \ + -c:v libx264 -t 2 -pix_fmt yuv420p -c:a aac -shortest /slates/offline.mp4 + fi # Debian cloud image: docker.io senza apparmor_parser → serve unconfined o pkg apparmor docker run -d --name mediamtx --restart unless-stopped --network host \ --security-opt apparmor=unconfined \