Merge pull request #70 from getpaseo/diagnostics/android-hang-cleanup-policy
Centralize perf diagnostics and activity coalescing
This commit is contained in:
@@ -97,6 +97,13 @@ const consoleLogger: Logger = {
|
||||
error: (obj, msg) => console.error(msg, obj),
|
||||
}
|
||||
|
||||
function getNowMs(): number {
|
||||
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
|
||||
return performance.now()
|
||||
}
|
||||
return Date.now()
|
||||
}
|
||||
|
||||
export type {
|
||||
DaemonTransport,
|
||||
DaemonTransportFactory,
|
||||
@@ -163,8 +170,26 @@ export type DaemonClientConfig = {
|
||||
baseDelayMs?: number
|
||||
maxDelayMs?: number
|
||||
}
|
||||
onDiagnosticsEvent?: (event: DaemonClientDiagnosticsEvent) => void
|
||||
}
|
||||
|
||||
export type DaemonClientDiagnosticsEvent =
|
||||
| {
|
||||
type: 'transport_message_timing'
|
||||
messageType: string
|
||||
payloadBytes: number
|
||||
parseMs: number
|
||||
validateMs: number
|
||||
totalMs: number
|
||||
outcome: 'ok' | 'parse_error' | 'validation_error'
|
||||
}
|
||||
| {
|
||||
type: 'transport_binary_frame'
|
||||
channel: BinaryMuxChannel
|
||||
messageType: number
|
||||
payloadBytes: number
|
||||
}
|
||||
|
||||
export type SendMessageOptions = {
|
||||
messageId?: string
|
||||
images?: Array<{ data: string; mimeType: string }>
|
||||
@@ -432,6 +457,14 @@ export class DaemonClient {
|
||||
})
|
||||
}
|
||||
|
||||
private emitDiagnosticsEvent(event: DaemonClientDiagnosticsEvent): void {
|
||||
try {
|
||||
this.config.onDiagnosticsEvent?.(event)
|
||||
} catch {
|
||||
// Diagnostics hooks must never break daemon message handling.
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Connection
|
||||
// ============================================================================
|
||||
@@ -2724,12 +2757,19 @@ export class DaemonClient {
|
||||
}
|
||||
|
||||
private handleTransportMessage(data: unknown): void {
|
||||
const startedAtMs = getNowMs()
|
||||
const rawData =
|
||||
data && typeof data === 'object' && 'data' in data ? (data as { data: unknown }).data : data
|
||||
const rawBytes = asUint8Array(rawData)
|
||||
if (rawBytes) {
|
||||
const frame = decodeBinaryMuxFrame(rawBytes)
|
||||
if (frame) {
|
||||
this.emitDiagnosticsEvent({
|
||||
type: 'transport_binary_frame',
|
||||
channel: frame.channel,
|
||||
messageType: frame.messageType,
|
||||
payloadBytes: frame.payload?.byteLength ?? 0,
|
||||
})
|
||||
this.handleBinaryFrame(frame)
|
||||
return
|
||||
}
|
||||
@@ -2740,19 +2780,52 @@ export class DaemonClient {
|
||||
}
|
||||
|
||||
let parsedJson: unknown
|
||||
let parseMs = 0
|
||||
try {
|
||||
const parseStartedAtMs = getNowMs()
|
||||
parsedJson = JSON.parse(payload)
|
||||
parseMs = getNowMs() - parseStartedAtMs
|
||||
} catch {
|
||||
this.emitDiagnosticsEvent({
|
||||
type: 'transport_message_timing',
|
||||
messageType: 'unknown',
|
||||
payloadBytes: payload.length,
|
||||
parseMs: 0,
|
||||
validateMs: 0,
|
||||
totalMs: getNowMs() - startedAtMs,
|
||||
outcome: 'parse_error',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const validateStartedAtMs = getNowMs()
|
||||
const parsed = WSOutboundMessageSchema.safeParse(parsedJson)
|
||||
const validateMs = getNowMs() - validateStartedAtMs
|
||||
if (!parsed.success) {
|
||||
const msgType = (parsedJson as { type?: string })?.type ?? 'unknown'
|
||||
this.emitDiagnosticsEvent({
|
||||
type: 'transport_message_timing',
|
||||
messageType: msgType,
|
||||
payloadBytes: payload.length,
|
||||
parseMs,
|
||||
validateMs,
|
||||
totalMs: getNowMs() - startedAtMs,
|
||||
outcome: 'validation_error',
|
||||
})
|
||||
this.logger.warn({ msgType, error: parsed.error.message }, 'Message validation failed')
|
||||
return
|
||||
}
|
||||
|
||||
this.emitDiagnosticsEvent({
|
||||
type: 'transport_message_timing',
|
||||
messageType: parsed.data.type,
|
||||
payloadBytes: payload.length,
|
||||
parseMs,
|
||||
validateMs,
|
||||
totalMs: getNowMs() - startedAtMs,
|
||||
outcome: 'ok',
|
||||
})
|
||||
|
||||
if (parsed.data.type === 'pong') {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user