Risolve timeout creazione sessione YouTube lato app.
La setup broadcast YouTube (~23s) passa in background job; l'API risponde subito. Aumentato anche il timeout Dio mobile per createSession YouTube. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
12
backend/app/jobs/youtube_broadcast_setup_job.rb
Normal file
12
backend/app/jobs/youtube_broadcast_setup_job.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
class YoutubeBroadcastSetupJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
retry_on Youtube::SetupBroadcast::Error, wait: 10.seconds, attempts: 3
|
||||
|
||||
def perform(session_id, youtube_channel = nil)
|
||||
session = StreamSession.find_by(id: session_id)
|
||||
return unless session
|
||||
|
||||
Youtube::SetupBroadcast.call(session, youtube_channel: youtube_channel.presence)
|
||||
end
|
||||
end
|
||||
@@ -27,10 +27,10 @@ module Sessions
|
||||
status: "idle"
|
||||
)
|
||||
|
||||
youtube_channel = nil
|
||||
if session.platform == "youtube"
|
||||
youtube_channel = @params[:youtube_channel].presence
|
||||
assert_youtube_channel!(youtube_channel)
|
||||
attach_youtube_broadcast!(session, youtube_channel: youtube_channel)
|
||||
end
|
||||
|
||||
StreamSession.transaction do
|
||||
@@ -40,10 +40,13 @@ module Sessions
|
||||
mtx.create_path(session)
|
||||
mtx.create_overlay_path(session)
|
||||
start_overlay_relay(session)
|
||||
start_youtube_relay(session)
|
||||
log_event(session, "pairing", { created: true, platform: session.platform })
|
||||
end
|
||||
|
||||
if session.platform == "youtube"
|
||||
YoutubeBroadcastSetupJob.perform_later(session.id, youtube_channel)
|
||||
end
|
||||
|
||||
session
|
||||
end
|
||||
|
||||
@@ -60,18 +63,7 @@ module Sessions
|
||||
end
|
||||
|
||||
def attach_youtube_broadcast!(session, youtube_channel: nil)
|
||||
yt = Youtube::BroadcastService.new(session.match.team, youtube_channel: youtube_channel)
|
||||
title = "#{session.match.team.name} vs #{session.match.opponent_name}"
|
||||
broadcast = yt.create_broadcast!(
|
||||
title: title,
|
||||
privacy_status: session.privacy_status,
|
||||
scheduled_at: session.match.scheduled_at
|
||||
)
|
||||
|
||||
session.youtube_broadcast_id = broadcast[:broadcast_id]
|
||||
session.youtube_stream_id = broadcast[:stream_id]
|
||||
session.stream_key = broadcast[:stream_key]
|
||||
session.rtmp_url = broadcast[:rtmp_url]
|
||||
Youtube::SetupBroadcast.call(session, youtube_channel: youtube_channel)
|
||||
end
|
||||
|
||||
def start_overlay_relay(session)
|
||||
@@ -80,14 +72,6 @@ module Sessions
|
||||
Rails.logger.warn("[Sessions::Create] Overlay relay: #{e.message}")
|
||||
end
|
||||
|
||||
def start_youtube_relay(session)
|
||||
return unless session.platform == "youtube"
|
||||
|
||||
Streams::YoutubeRelay.start(session)
|
||||
rescue Streams::YoutubeRelay::Error => e
|
||||
Rails.logger.warn("[Sessions::Create] YouTube relay: #{e.message}")
|
||||
end
|
||||
|
||||
def log_event(session, type, metadata)
|
||||
session.stream_events.create!(event_type: type, metadata: metadata, occurred_at: Time.current)
|
||||
end
|
||||
|
||||
52
backend/app/services/youtube/setup_broadcast.rb
Normal file
52
backend/app/services/youtube/setup_broadcast.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
module Youtube
|
||||
# Crea broadcast/stream YouTube e avvia relay (operazione lenta, ~20s).
|
||||
class SetupBroadcast
|
||||
class Error < StandardError; end
|
||||
|
||||
def self.call(session, youtube_channel: nil)
|
||||
new(session, youtube_channel: youtube_channel).call
|
||||
end
|
||||
|
||||
def initialize(session, youtube_channel: nil)
|
||||
@session = session
|
||||
@youtube_channel = youtube_channel
|
||||
end
|
||||
|
||||
def call
|
||||
@session.reload
|
||||
return @session if @session.terminal?
|
||||
return @session if @session.platform != "youtube"
|
||||
return @session if @session.youtube_broadcast_id.present?
|
||||
|
||||
yt = BroadcastService.new(@session.match.team, channel: @youtube_channel)
|
||||
title = "#{@session.match.team.name} vs #{@session.match.opponent_name}"
|
||||
broadcast = yt.create_broadcast!(
|
||||
title: title,
|
||||
privacy_status: @session.privacy_status,
|
||||
scheduled_at: @session.match.scheduled_at
|
||||
)
|
||||
|
||||
@session.update!(
|
||||
youtube_broadcast_id: broadcast[:broadcast_id],
|
||||
youtube_stream_id: broadcast[:stream_id],
|
||||
stream_key: broadcast[:stream_key],
|
||||
rtmp_url: broadcast[:rtmp_url]
|
||||
)
|
||||
|
||||
Streams::YoutubeRelay.start(@session)
|
||||
@session.stream_events.create!(
|
||||
event_type: "youtube_ready",
|
||||
metadata: { broadcast_id: broadcast[:broadcast_id] },
|
||||
occurred_at: Time.current
|
||||
)
|
||||
@session
|
||||
rescue BroadcastService::Error => e
|
||||
@session.stream_events.create!(
|
||||
event_type: "error",
|
||||
metadata: { source: "youtube_setup", message: e.message },
|
||||
occurred_at: Time.current
|
||||
)
|
||||
raise Error, e.message
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -76,6 +76,17 @@ class _StepTransmissionState extends ConsumerState<StepTransmission> {
|
||||
message: apiErr!.message,
|
||||
billingUrl: apiErr.billingUrl,
|
||||
);
|
||||
} else if (e.type == DioExceptionType.receiveTimeout ||
|
||||
e.type == DioExceptionType.sendTimeout ||
|
||||
e.type == DioExceptionType.connectionTimeout) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
'Il server impiega più del previsto (YouTube). Attendi e non ritentare subito: '
|
||||
'controlla se la sessione è già stata creata.',
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(apiErr?.message ?? 'Errore nella creazione sessione')),
|
||||
|
||||
@@ -167,6 +167,10 @@ class ApiClient {
|
||||
int? targetBitrate,
|
||||
int? targetFps,
|
||||
}) async {
|
||||
// YouTube: creazione broadcast + path MediaMTX può richiedere 20–30s lato server.
|
||||
final sessionTimeout = platform == 'youtube'
|
||||
? const Duration(seconds: 60)
|
||||
: const Duration(seconds: 30);
|
||||
final response = await _dio.post<Map<String, dynamic>>(
|
||||
'/matches/$matchId/sessions',
|
||||
data: {
|
||||
@@ -177,6 +181,10 @@ class ApiClient {
|
||||
if (targetBitrate != null) 'target_bitrate': targetBitrate,
|
||||
if (targetFps != null) 'target_fps': targetFps,
|
||||
},
|
||||
options: Options(
|
||||
sendTimeout: sessionTimeout,
|
||||
receiveTimeout: sessionTimeout,
|
||||
),
|
||||
);
|
||||
return StreamSession.fromJson(response.data!);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user