Evita 500 senza SMTP e chiude gli incidenti overflow stale.
Reset password e mail replay usano deliver_mail; il health check overflow risolve tutte le fingerprint del kind, non solo quella sana. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -54,6 +54,8 @@ module Ops
|
|||||||
def process_finding(finding)
|
def process_finding(finding)
|
||||||
if finding.healthy
|
if finding.healthy
|
||||||
Ops::IncidentRecorder.resolve(fingerprint: finding.fingerprint)
|
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
|
else
|
||||||
Ops::IncidentRecorder.record(
|
Ops::IncidentRecorder.record(
|
||||||
kind: finding.kind,
|
kind: finding.kind,
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ module Ops
|
|||||||
def resolve(fingerprint:)
|
def resolve(fingerprint:)
|
||||||
new.resolve(fingerprint: fingerprint)
|
new.resolve(fingerprint: fingerprint)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resolve_kind(kind)
|
||||||
|
new.resolve_kind(kind)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def record(finding)
|
def record(finding)
|
||||||
@@ -49,6 +53,10 @@ module Ops
|
|||||||
Ops::Incident.open.where(fingerprint: fingerprint).find_each(&:resolve!)
|
Ops::Incident.open.where(fingerprint: fingerprint).find_each(&:resolve!)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resolve_kind(kind)
|
||||||
|
Ops::Incident.open.where(kind: kind).find_each(&:resolve!)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def fingerprint_for(finding)
|
def fingerprint_for(finding)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ module Recordings
|
|||||||
private
|
private
|
||||||
|
|
||||||
def deliver_expiring_soon(user)
|
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
|
rescue EOFError => e
|
||||||
Rails.logger.warn("[Recordings::NotifyExpiring] SMTP EOF on close for #{user.email}: #{e.message}")
|
Rails.logger.warn("[Recordings::NotifyExpiring] SMTP EOF on close for #{user.email}: #{e.message}")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ module Recordings
|
|||||||
private
|
private
|
||||||
|
|
||||||
def deliver_replay_ready(user)
|
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
|
rescue EOFError => e
|
||||||
# Aruba SMTP (465/SSL) chiude la socket prima del QUIT: la mail è già partita.
|
# 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}")
|
Rails.logger.warn("[Recordings::NotifyReady] SMTP EOF on close for #{user.email}: #{e.message}")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ module Users
|
|||||||
return if user.nil?
|
return if user.nil?
|
||||||
|
|
||||||
token = user.generate_password_reset!
|
token = user.generate_password_reset!
|
||||||
UserMailer.password_reset(user, token).deliver_now
|
MatchLiveTv.deliver_mail(UserMailer.password_reset(user, token))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -109,6 +109,17 @@ RSpec.describe "Account API", type: :request do
|
|||||||
expect(user.reload.password_reset_digest).to be_present
|
expect(user.reload.password_reset_digest).to be_present
|
||||||
end
|
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
|
it "returns the same message for unknown emails" do
|
||||||
expect {
|
expect {
|
||||||
post "/api/v1/auth/password/forgot", params: { email: "nobody@example.com" }
|
post "/api/v1/auth/password/forgot", params: { email: "nobody@example.com" }
|
||||||
|
|||||||
@@ -40,6 +40,44 @@ RSpec.describe Ops::HealthChecks do
|
|||||||
|
|
||||||
expect(Ops::Incident.find_by(fingerprint: "disk_space:root").status).to eq("resolved")
|
expect(Ops::Incident.find_by(fingerprint: "disk_space:root").status).to eq("resolved")
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
describe "#summary" do
|
describe "#summary" do
|
||||||
|
|||||||
@@ -52,4 +52,28 @@ RSpec.describe Ops::IncidentRecorder do
|
|||||||
expect(incident.reload.status).to eq("resolved")
|
expect(incident.reload.status).to eq("resolved")
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|||||||
@@ -27,4 +27,22 @@ RSpec.describe Recordings::NotifyReady do
|
|||||||
|
|
||||||
expect(recording.reload.ready_notified_at).to be_present
|
expect(recording.reload.ready_notified_at).to be_present
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user