tts: make ensure route abort-aware and reduce abort log noise

This commit is contained in:
Richard R 2026-05-21 16:46:47 -06:00
parent 3c25c93e8b
commit 3ebcb3e6fd

View file

@ -329,6 +329,16 @@ export async function POST(request: NextRequest) {
}; };
for (const segment of normalized) { for (const segment of normalized) {
if (request.signal.aborted) {
console.info('[tts-segments/ensure] request aborted; stopping remaining segment processing', {
requestId,
documentId: parsed.documentId,
completedSoFar: manifest.length,
totalRequested: normalized.length,
});
break;
}
const segmentStartedAt = Date.now(); const segmentStartedAt = Date.now();
const stageTimings: Record<string, number> = {}; const stageTimings: Record<string, number> = {};
let failedStage = 'unknown'; let failedStage = 'unknown';
@ -382,7 +392,7 @@ export async function POST(request: NextRequest) {
// Self-heal transient Whisper failures: if audio exists but alignment was // Self-heal transient Whisper failures: if audio exists but alignment was
// previously unavailable, retry alignment using the current segment text. // previously unavailable, retry alignment using the current segment text.
if (!alignment) { if (!alignment && !request.signal.aborted) {
try { try {
const alignStartedAt = Date.now(); const alignStartedAt = Date.now();
const computeBackend = await getComputeBackend(); const computeBackend = await getComputeBackend();
@ -406,9 +416,12 @@ export async function POST(request: NextRequest) {
)); ));
} }
} catch (alignError) { } catch (alignError) {
console.warn('Whisper alignment still unavailable for completed segment; continuing without word highlights.', { const aborted = isAbortLikeError(alignError) || request.signal.aborted;
const log = aborted ? console.info : console.warn;
log('Whisper alignment still unavailable for completed segment; continuing without word highlights.', {
requestId, requestId,
segmentId: segment.segmentId, segmentId: segment.segmentId,
aborted,
error: alignError instanceof Error ? alignError.message : String(alignError), error: alignError instanceof Error ? alignError.message : String(alignError),
}); });
alignment = null; alignment = null;
@ -632,23 +645,28 @@ export async function POST(request: NextRequest) {
const durationMs = await probeAudioDurationMsFromBuffer(persistedBuffer, request.signal); const durationMs = await probeAudioDurationMsFromBuffer(persistedBuffer, request.signal);
stageTimings.probeDurationMs = Date.now() - probeStartedAt; stageTimings.probeDurationMs = Date.now() - probeStartedAt;
let alignment: TTSSegmentManifestItem['alignment'] = null; let alignment: TTSSegmentManifestItem['alignment'] = null;
try { if (!request.signal.aborted) {
failedStage = 'whisper.align'; try {
const alignStartedAt = Date.now(); failedStage = 'whisper.align';
const computeBackend = await getComputeBackend(); const alignStartedAt = Date.now();
const aligned = (await computeBackend.alignWords({ const computeBackend = await getComputeBackend();
audioObjectKey: audioKey, const aligned = (await computeBackend.alignWords({
text: segment.text, audioObjectKey: audioKey,
})).alignments; text: segment.text,
stageTimings.whisperAlignMs = Date.now() - alignStartedAt; })).alignments;
alignment = aligned[0] ? { ...aligned[0], sentenceIndex: segment.original.segmentIndex } : null; stageTimings.whisperAlignMs = Date.now() - alignStartedAt;
} catch (alignError) { alignment = aligned[0] ? { ...aligned[0], sentenceIndex: segment.original.segmentIndex } : null;
console.warn('Whisper alignment unavailable for segment; continuing without word highlights.', { } catch (alignError) {
requestId, const aborted = isAbortLikeError(alignError) || request.signal.aborted;
segmentId: segment.segmentId, const log = aborted ? console.info : console.warn;
error: alignError instanceof Error ? alignError.message : String(alignError), log('Whisper alignment unavailable for segment; continuing without word highlights.', {
}); requestId,
alignment = null; segmentId: segment.segmentId,
aborted,
error: alignError instanceof Error ? alignError.message : String(alignError),
});
alignment = null;
}
} }
failedStage = 'db.mark_completed'; failedStage = 'db.mark_completed';
@ -699,7 +717,8 @@ export async function POST(request: NextRequest) {
: upstreamStatus && upstreamStatus >= 500 : upstreamStatus && upstreamStatus >= 500
? 'UPSTREAM_TTS_ERROR' ? 'UPSTREAM_TTS_ERROR'
: 'TTS_SEGMENT_GENERATION_FAILED'; : 'TTS_SEGMENT_GENERATION_FAILED';
console.error('[tts-segments/ensure] segment failed', { const segmentFailureLog = aborted ? console.info : console.error;
segmentFailureLog('[tts-segments/ensure] segment failed', {
requestId, requestId,
documentId: parsed.documentId, documentId: parsed.documentId,
segmentId: segment.segmentId, segmentId: segment.segmentId,
@ -747,6 +766,17 @@ export async function POST(request: NextRequest) {
...(typeof retryAfterSeconds === 'number' ? { retryAfterSeconds } : {}), ...(typeof retryAfterSeconds === 'number' ? { retryAfterSeconds } : {}),
}, },
}); });
if (aborted || request.signal.aborted) {
console.info('[tts-segments/ensure] stopping remaining segments after abort', {
requestId,
documentId: parsed.documentId,
segmentId: segment.segmentId,
completedSoFar: manifest.length,
totalRequested: normalized.length,
});
break;
}
} }
} }