Fix stuck recording processing and add invoice service API test.
Deploy Ladill Meet / deploy (push) Successful in 52s
Deploy Ladill Meet / deploy (push) Successful in 52s
Capture stage spotlight video for browser recordings, fail incomplete uploads, allow post-session host uploads, and expire stale processing recordings automatically. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -121,6 +121,80 @@ class RecordingService
|
||||
return $recording->fresh();
|
||||
}
|
||||
|
||||
public function fail(Recording $recording, string $reason, ?string $actorRef = null): Recording
|
||||
{
|
||||
if (! in_array($recording->status, ['recording', 'processing'], true)) {
|
||||
return $recording;
|
||||
}
|
||||
|
||||
$recording->update([
|
||||
'status' => 'failed',
|
||||
'failure_reason' => $reason,
|
||||
'ended_at' => $recording->ended_at ?? now(),
|
||||
'duration_seconds' => $recording->duration_seconds
|
||||
?? ($recording->started_at ? (int) $recording->started_at->diffInSeconds(now()) : null),
|
||||
]);
|
||||
|
||||
if ($actorRef) {
|
||||
AuditLogger::record(
|
||||
$recording->owner_ref,
|
||||
'recording.failed',
|
||||
$recording->session->room->organization_id,
|
||||
$actorRef,
|
||||
Recording::class,
|
||||
$recording->id,
|
||||
);
|
||||
}
|
||||
|
||||
return $recording->fresh();
|
||||
}
|
||||
|
||||
/** Fail recordings left in processing long after the meeting ended. */
|
||||
public function resolveProcessingState(Recording $recording): Recording
|
||||
{
|
||||
if ($recording->status !== 'processing') {
|
||||
return $this->ensureStorageValid($recording);
|
||||
}
|
||||
|
||||
$timeoutMinutes = max(5, (int) config('meet.recordings.processing_timeout_minutes', 15));
|
||||
$staleAt = $recording->ended_at ?? $recording->updated_at;
|
||||
|
||||
if ($staleAt && $staleAt->lt(now()->subMinutes($timeoutMinutes))) {
|
||||
return $this->fail(
|
||||
$recording,
|
||||
'Recording upload did not complete. Keep the host browser open briefly after ending the meeting so the file can upload.',
|
||||
);
|
||||
}
|
||||
|
||||
return $recording;
|
||||
}
|
||||
|
||||
public function failStaleProcessingRecordings(?int $timeoutMinutes = null): int
|
||||
{
|
||||
$timeoutMinutes = max(5, $timeoutMinutes ?? (int) config('meet.recordings.processing_timeout_minutes', 15));
|
||||
$cutoff = now()->subMinutes($timeoutMinutes);
|
||||
$failed = 0;
|
||||
|
||||
Recording::query()
|
||||
->where('status', 'processing')
|
||||
->where(function ($query) use ($cutoff) {
|
||||
$query->where('ended_at', '<', $cutoff)
|
||||
->orWhere(function ($query) use ($cutoff) {
|
||||
$query->whereNull('ended_at')->where('updated_at', '<', $cutoff);
|
||||
});
|
||||
})
|
||||
->orderBy('id')
|
||||
->each(function (Recording $recording) use (&$failed) {
|
||||
$this->fail(
|
||||
$recording,
|
||||
'Recording upload did not complete. Keep the host browser open briefly after ending the meeting so the file can upload.',
|
||||
);
|
||||
$failed++;
|
||||
});
|
||||
|
||||
return $failed;
|
||||
}
|
||||
|
||||
/** Mark ready recordings with missing/empty files as failed. */
|
||||
public function ensureStorageValid(Recording $recording): Recording
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user