fix(perf): exclude profiler flush from cancel latency

This commit is contained in:
4gray committed 2026-07-26 23:14:57 +02:00
1 parent 8bafd62932
commit df7eee7e52
3 files changed
+46 -22

No files matched your search

@@ -178,6 +178,20 @@ async function executeRefresh(
checkpoint(payload);
return playlist;
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
emitEvent(payload, {
status: 'cancelled',
phase: 'parsing',
});
} else {
emitEvent(payload, {
status: 'error',
phase: payload.url ? 'fetching' : 'reading-file',
error: error instanceof Error ? error.message : String(error),
});
}
throw error;
} finally {
releaseActiveRefresh(payload.operationId, activeRefresh);
}
@@ -219,22 +233,6 @@ parentPort.on(
});
} else {
const error = execution.error;
if (error instanceof Error && error.name === 'AbortError') {
emitEvent(payload, {
status: 'cancelled',
phase: 'parsing',
});
} else {
emitEvent(payload, {
status: 'error',
phase: payload.url ? 'fetching' : 'reading-file',
error:
error instanceof Error
? error.message
: String(error),
});
}
postMessage({
type: 'response',
success: false,
@@ -50,7 +50,13 @@ function createParentPortHarness<TIncoming, TOutgoing>() {
};
}
function mockPerformanceCapture(armGate: ArmGate): void {
function mockPerformanceCapture(
armGate: ArmGate,
failureGates?: {
readonly observed: ArmGate;
readonly profilingFinished: ArmGate;
}
): void {
jest.doMock('./worker-performance-capture', () => ({
armWorkerPerformanceCapture: jest.fn(() => armGate.promise),
executeWithWorkerPerformanceCapture: jest.fn(
@@ -63,6 +69,8 @@ function mockPerformanceCapture(armGate: ArmGate): void {
success: true,
};
} catch (error) {
failureGates?.observed.release();
await failureGates?.profilingFinished.promise;
return {
error,
performance: undefined,
@@ -86,12 +94,17 @@ describe('worker cancellation while performance capture arms', () => {
it('cancels playlist work before file access when cancel arrives during arming', async () => {
const armGate = createArmGate();
const profilingFinished = createArmGate();
const failureObserved = createArmGate();
const port = createParentPortHarness<
PlaylistRefreshWorkerIncomingMessage,
PlaylistRefreshWorkerMessage<unknown>
>();
const readFile = jest.fn().mockResolvedValue('#EXTM3U');
mockPerformanceCapture(armGate);
mockPerformanceCapture(armGate, {
observed: failureObserved,
profilingFinished,
});
jest.doMock('worker_threads', () => ({
parentPort: port.parentPort,
}));
@@ -122,9 +135,25 @@ describe('worker cancellation while performance capture arms', () => {
operationId: 'refresh-1',
});
armGate.release();
await failureObserved.promise;
const cancelledBeforeProfilingFinished =
port.postMessage.mock.calls.some(
([message]) =>
message.type === 'event' &&
message.event.status === 'cancelled'
);
const responseBeforeProfilingFinished =
port.postMessage.mock.calls.some(
([message]) => message.type === 'response'
);
profilingFinished.release();
await requestPromise;
expect(readFile).not.toHaveBeenCalled();
expect(cancelledBeforeProfilingFinished).toBe(true);
expect(responseBeforeProfilingFinished).toBe(false);
expect(port.postMessage).toHaveBeenCalledWith(
expect.objectContaining({
event: expect.objectContaining({
@@ -37,7 +37,7 @@ describe('worker performance integration order', () => {
expect(handler).not.toContain('requestQueue');
});
it('finishes playlist profiling before cancellation/error events and response serialization', () => {
it('keeps playlist response serialization after profiling completion', () => {
const source = readWorkerSource('playlist-refresh.worker.ts');
const handler = source.slice(source.lastIndexOf('parentPort.on('));
const executionIndex = handler.indexOf(
@@ -46,9 +46,6 @@ describe('worker performance integration order', () => {
expect(executionIndex).toBeGreaterThanOrEqual(0);
expect(handler).not.toContain('finishWorkerPerformanceCapture');
expect(executionIndex).toBeLessThan(
handler.indexOf('emitEvent', executionIndex)
);
expect(executionIndex).toBeLessThan(
handler.indexOf('serializeError', executionIndex)
);