diff --git a/backend/app/services/ops/health_checks.rb b/backend/app/services/ops/health_checks.rb index 8194b01..51d9250 100644 --- a/backend/app/services/ops/health_checks.rb +++ b/backend/app/services/ops/health_checks.rb @@ -54,6 +54,8 @@ module Ops def process_finding(finding) if finding.healthy Ops::IncidentRecorder.resolve(fingerprint: finding.fingerprint) + # overflow usa fingerprint diverse (at_max / orphan_idle / budget) rispetto al check sano + Ops::IncidentRecorder.resolve_kind(finding.kind) if finding.kind == "stream_overflow" else Ops::IncidentRecorder.record( kind: finding.kind, diff --git a/backend/app/services/ops/incident_recorder.rb b/backend/app/services/ops/incident_recorder.rb index d0c86d2..dbb5cef 100644 --- a/backend/app/services/ops/incident_recorder.rb +++ b/backend/app/services/ops/incident_recorder.rb @@ -10,6 +10,10 @@ module Ops def resolve(fingerprint:) new.resolve(fingerprint: fingerprint) end + + def resolve_kind(kind) + new.resolve_kind(kind) + end end def record(finding) @@ -49,6 +53,10 @@ module Ops Ops::Incident.open.where(fingerprint: fingerprint).find_each(&:resolve!) end + def resolve_kind(kind) + Ops::Incident.open.where(kind: kind).find_each(&:resolve!) + end + private def fingerprint_for(finding) diff --git a/backend/app/services/recordings/notify_expiring.rb b/backend/app/services/recordings/notify_expiring.rb index c872505..20f6d48 100644 --- a/backend/app/services/recordings/notify_expiring.rb +++ b/backend/app/services/recordings/notify_expiring.rb @@ -23,7 +23,7 @@ module Recordings private def deliver_expiring_soon(user) - Recordings::ReplayMailer.replay_expiring_soon(recording: @recording, recipient: user).deliver_now + MatchLiveTv.deliver_mail(Recordings::ReplayMailer.replay_expiring_soon(recording: @recording, recipient: user)) rescue EOFError => e Rails.logger.warn("[Recordings::NotifyExpiring] SMTP EOF on close for #{user.email}: #{e.message}") end diff --git a/backend/app/services/recordings/notify_ready.rb b/backend/app/services/recordings/notify_ready.rb index 4ad26cf..fde7b40 100644 --- a/backend/app/services/recordings/notify_ready.rb +++ b/backend/app/services/recordings/notify_ready.rb @@ -19,7 +19,7 @@ module Recordings private def deliver_replay_ready(user) - Recordings::ReplayMailer.replay_ready(recording: @recording, recipient: user).deliver_now + MatchLiveTv.deliver_mail(Recordings::ReplayMailer.replay_ready(recording: @recording, recipient: user)) rescue EOFError => e # Aruba SMTP (465/SSL) chiude la socket prima del QUIT: la mail è già partita. Rails.logger.warn("[Recordings::NotifyReady] SMTP EOF on close for #{user.email}: #{e.message}") diff --git a/backend/app/services/users/request_password_reset.rb b/backend/app/services/users/request_password_reset.rb index 4c73b93..c62c2ed 100644 --- a/backend/app/services/users/request_password_reset.rb +++ b/backend/app/services/users/request_password_reset.rb @@ -13,7 +13,7 @@ module Users return if user.nil? token = user.generate_password_reset! - UserMailer.password_reset(user, token).deliver_now + MatchLiveTv.deliver_mail(UserMailer.password_reset(user, token)) end end end diff --git a/backend/spec/requests/account_spec.rb b/backend/spec/requests/account_spec.rb index 2dc7742..118840c 100644 --- a/backend/spec/requests/account_spec.rb +++ b/backend/spec/requests/account_spec.rb @@ -109,6 +109,17 @@ RSpec.describe "Account API", type: :request do expect(user.reload.password_reset_digest).to be_present end + it "non va in 500 se in produzione manca SMTP" do + allow(MatchLiveTv).to receive(:smtp_configured?).and_return(false) + allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production")) + + expect { + post "/api/v1/auth/password/forgot", params: { email: user.email } + }.not_to change { ActionMailer::Base.deliveries.size } + expect(response).to have_http_status(:ok) + expect(user.reload.password_reset_digest).to be_present + end + it "returns the same message for unknown emails" do expect { post "/api/v1/auth/password/forgot", params: { email: "nobody@example.com" } diff --git a/backend/spec/services/ops/health_checks_spec.rb b/backend/spec/services/ops/health_checks_spec.rb index cbd7471..8e1c4bc 100644 --- a/backend/spec/services/ops/health_checks_spec.rb +++ b/backend/spec/services/ops/health_checks_spec.rb @@ -40,6 +40,44 @@ RSpec.describe Ops::HealthChecks do expect(Ops::Incident.find_by(fingerprint: "disk_space:root").status).to eq("resolved") end + + it "chiude gli incidenti overflow anche se la fingerprint sana è diversa" do + Ops::Incident.create!( + kind: "stream_overflow", + severity: "warning", + status: "open", + title: "Capacità stream al massimo", + message: "overflow=3/3", + metadata: {}, + fingerprint: "stream_overflow:at_max", + occurrence_count: 1, + first_seen_at: Time.current, + last_seen_at: Time.current + ) + + allow_any_instance_of(described_class).to receive(:check_stream_overflow).and_return( + described_class::Finding.new( + kind: "stream_overflow", severity: "info", healthy: true, + title: "Overflow streaming OK", message: "OK", metadata: {}, fingerprint: "stream_overflow:ok" + ) + ) + %i[ + check_disk_root check_recordings_size check_postgres check_redis check_mediamtx check_garage + check_sidekiq_heartbeat check_sidekiq_dead check_http_rails check_rails_latency + ].each do |method| + allow_any_instance_of(described_class).to receive(method).and_return( + described_class::Finding.new( + kind: "test", severity: "info", healthy: true, + title: "OK", message: "OK", metadata: {}, fingerprint: "#{method}:ok" + ) + ) + end + allow_any_instance_of(described_class).to receive(:public_check_due?).and_return(false) + + described_class.new.call + + expect(Ops::Incident.find_by(fingerprint: "stream_overflow:at_max").status).to eq("resolved") + end end describe "#summary" do diff --git a/backend/spec/services/ops/incident_recorder_spec.rb b/backend/spec/services/ops/incident_recorder_spec.rb index c62a052..1400348 100644 --- a/backend/spec/services/ops/incident_recorder_spec.rb +++ b/backend/spec/services/ops/incident_recorder_spec.rb @@ -52,4 +52,28 @@ RSpec.describe Ops::IncidentRecorder do expect(incident.reload.status).to eq("resolved") end end + + describe ".resolve_kind" do + it "chiude tutti gli incidenti aperti di quel kind" do + at_max = described_class.record( + kind: "stream_overflow", + severity: "warning", + title: "Max", + message: "max", + fingerprint: "stream_overflow:at_max" + ) + orphan = described_class.record( + kind: "stream_overflow", + severity: "warning", + title: "Idle", + message: "idle", + fingerprint: "stream_overflow:orphan_idle" + ) + + described_class.resolve_kind("stream_overflow") + + expect(at_max.reload.status).to eq("resolved") + expect(orphan.reload.status).to eq("resolved") + end + end end diff --git a/backend/spec/services/recordings/notify_ready_spec.rb b/backend/spec/services/recordings/notify_ready_spec.rb index 834d1c0..59acda1 100644 --- a/backend/spec/services/recordings/notify_ready_spec.rb +++ b/backend/spec/services/recordings/notify_ready_spec.rb @@ -27,4 +27,22 @@ RSpec.describe Recordings::NotifyReady do expect(recording.reload.ready_notified_at).to be_present end + + it "marca notificato anche se in produzione manca SMTP" do + recording = Recording.create!( + stream_session: session, + team: team, + status: "ready", + expires_at: 10.days.from_now, + storage_key: "key" + ) + allow(MatchLiveTv).to receive(:smtp_configured?).and_return(false) + allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production")) + + expect { + described_class.new(recording).call + }.not_to change { ActionMailer::Base.deliveries.size } + + expect(recording.reload.ready_notified_at).to be_present + end end