perf: optimize app startup and background lifecycles
This commit is contained in:
1 parent
31332f6d76
commit
927e13349b
121 files changed
+4359
-1400
No files matched your search
@@ -0,0 +1,90 @@
|
||||
import { parentPort } from 'electron';
|
||||
import {
|
||||
prepareProjectReleaseSummary,
|
||||
ProjectReleaseBuildError,
|
||||
type ReleaseBuildRuntimeContext,
|
||||
} from './project-release-builder';
|
||||
|
||||
type StartMessage = {
|
||||
type: 'start';
|
||||
jobId: string;
|
||||
projectPath: string;
|
||||
clientVersion: string;
|
||||
runtimeContext: ReleaseBuildRuntimeContext;
|
||||
};
|
||||
|
||||
type CancelMessage = {
|
||||
type: 'cancel';
|
||||
jobId: string;
|
||||
};
|
||||
|
||||
type WorkerMessage = StartMessage | CancelMessage;
|
||||
|
||||
const controllers = new Map<string, AbortController>();
|
||||
|
||||
function readMessage(value: unknown): WorkerMessage | null {
|
||||
const candidate = value && typeof value === 'object' && 'data' in value
|
||||
? (value as { data?: unknown }).data
|
||||
: value;
|
||||
if (!candidate || typeof candidate !== 'object') return null;
|
||||
const message = candidate as Partial<WorkerMessage>;
|
||||
if (message.type !== 'start' && message.type !== 'cancel') return null;
|
||||
return message as WorkerMessage;
|
||||
}
|
||||
|
||||
function post(message: unknown): void {
|
||||
parentPort?.postMessage(message);
|
||||
}
|
||||
|
||||
async function run(message: StartMessage): Promise<void> {
|
||||
const controller = new AbortController();
|
||||
controllers.set(message.jobId, controller);
|
||||
try {
|
||||
const prepared = await prepareProjectReleaseSummary({
|
||||
projectPath: message.projectPath,
|
||||
clientVersion: message.clientVersion,
|
||||
runtimeContext: message.runtimeContext,
|
||||
signal: controller.signal,
|
||||
onProgress: (progress) => post({ type: 'progress', jobId: message.jobId, progress }),
|
||||
});
|
||||
try {
|
||||
if (controller.signal.aborted) {
|
||||
throw new ProjectReleaseBuildError('LOCAL_BUILD_CANCELLED');
|
||||
}
|
||||
post({
|
||||
type: 'complete',
|
||||
jobId: message.jobId,
|
||||
packageSummary: prepared.sourceArchive.summary,
|
||||
contract: prepared.contract,
|
||||
});
|
||||
} finally {
|
||||
await prepared.dispose();
|
||||
}
|
||||
} catch (error) {
|
||||
const code = error instanceof ProjectReleaseBuildError
|
||||
? error.code
|
||||
: 'LOCAL_BUILD_FAILED';
|
||||
post({
|
||||
type: 'error',
|
||||
jobId: message.jobId,
|
||||
code,
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
} finally {
|
||||
controllers.delete(message.jobId);
|
||||
// The worker is single-job by design. Exiting here releases any native
|
||||
// module state and makes the process count observable and bounded.
|
||||
setImmediate(() => process.exit(0));
|
||||
}
|
||||
}
|
||||
|
||||
parentPort?.on('message', (value) => {
|
||||
const message = readMessage(value);
|
||||
if (!message) return;
|
||||
if (message.type === 'cancel') {
|
||||
controllers.get(message.jobId)?.abort();
|
||||
return;
|
||||
}
|
||||
if (controllers.has(message.jobId)) return;
|
||||
void run(message);
|
||||
});
|
||||
Reference in new issue
Block a user