fix(voice): resolve Redis subscriber corruption, transmitter races, and DB error logging

Redis root cause: VoiceHandler passed redisPub to transmitter.start(),
which called .subscribe() on it — permanently converting the publish
connection to subscriber mode. Every subsequent command reply and status
update failed.

Fixes:
1. Transmitter now creates its own Redis client via new IORedis()
2. Mutual exclusion gate serialises start/stop to prevent null-deref races
3. PassThrough drain listeners cleaned up to stop MaxListenersExceeded
4. FFmpeg SIGTERM flagged as expected exit (no more false level-50 errors)
5. Voice recording repo captures PG error code/detail for diagnostics

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-14 04:23:04 +07:00
co-authored by Claude
parent 32b0b20ca7
commit dbc2879e16
4 changed files with 121 additions and 130 deletions
@@ -40,19 +40,13 @@ export async function insertVoiceRecording(
.values(recording)
.onConflictDoNothing();
} catch (error) {
const detail =
error instanceof Error
? {
message: error.message,
name: error.name,
...((error as Record<string, unknown>).code !== undefined
? { code: (error as Record<string, unknown>).code }
: {}),
...((error as Record<string, unknown>).detail !== undefined
? { detail: (error as Record<string, unknown>).detail }
: {}),
}
: String(error);
const err = error as Record<string, unknown>;
const detail: Record<string, unknown> = {
message: error instanceof Error ? error.message : String(error),
name: error instanceof Error ? error.name : undefined,
};
if (err.code !== undefined) detail.code = err.code;
if (err.detail !== undefined) detail.detail = err.detail;
logger.error(
{ id: recording.id, error: detail },
"Failed to insert voice recording",