Skip to content

Commit 54a80fe

Browse files
authored
fix: improve event system for inference servers (#886)
Signed-off-by: axel7083 <[email protected]>
1 parent e254307 commit 54a80fe

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

packages/backend/src/managers/inference/inferenceManager.spec.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,3 +538,88 @@ describe('Request Create Inference Server', () => {
538538
});
539539
});
540540
});
541+
542+
describe('containerRegistry events', () => {
543+
test('container die event', async () => {
544+
mockListContainers([
545+
{
546+
Id: 'dummyId',
547+
engineId: 'dummyEngineId',
548+
Labels: {
549+
[LABEL_INFERENCE_SERVER]: '[]',
550+
},
551+
},
552+
]);
553+
const disposableMock = vi.fn();
554+
const deferred = new Promise<(status: string) => void>((resolve, reject) => {
555+
vi.mocked(containerRegistryMock.subscribe).mockImplementation((containerId, listener) => {
556+
if (containerId !== 'dummyId') reject(new Error('invalid container id'));
557+
else resolve(listener);
558+
return {
559+
dispose: disposableMock,
560+
};
561+
});
562+
});
563+
564+
const inferenceManager = await getInitializedInferenceManager();
565+
const listener = await deferred;
566+
567+
const server = inferenceManager.get('dummyId');
568+
expect(server.status).toBe('running');
569+
expect(containerEngine.inspectContainer).toHaveBeenCalledOnce();
570+
571+
vi.mocked(containerEngine.inspectContainer).mockResolvedValue({
572+
State: {
573+
Status: 'stopped',
574+
Health: undefined,
575+
},
576+
} as unknown as ContainerInspectInfo);
577+
578+
listener('die');
579+
580+
await vi.waitFor(() => {
581+
expect(inferenceManager.get('dummyId').status).toBe('stopped');
582+
expect(containerEngine.inspectContainer).toHaveBeenCalledTimes(2);
583+
});
584+
585+
// we should not have disposed the subscriber, as the container is only stopped, not removed
586+
expect(disposableMock).not.toHaveBeenCalled();
587+
});
588+
589+
test('container remove event', async () => {
590+
mockListContainers([
591+
{
592+
Id: 'dummyId',
593+
engineId: 'dummyEngineId',
594+
Labels: {
595+
[LABEL_INFERENCE_SERVER]: '[]',
596+
},
597+
},
598+
]);
599+
const disposableMock = vi.fn();
600+
const deferred = new Promise<(status: string) => void>((resolve, reject) => {
601+
vi.mocked(containerRegistryMock.subscribe).mockImplementation((containerId, listener) => {
602+
if (containerId !== 'dummyId') reject(new Error('invalid container id'));
603+
else resolve(listener);
604+
return {
605+
dispose: disposableMock,
606+
};
607+
});
608+
});
609+
610+
const inferenceManager = await getInitializedInferenceManager();
611+
const listener = await deferred;
612+
613+
const server = inferenceManager.get('dummyId');
614+
expect(server.status).toBe('running');
615+
616+
listener('remove');
617+
618+
await vi.waitFor(() => {
619+
expect(inferenceManager.get('dummyId')).toBeUndefined();
620+
});
621+
622+
// we should have disposed the subscriber, as the container is removed
623+
expect(disposableMock).toHaveBeenCalled();
624+
});
625+
});

packages/backend/src/managers/inference/inferenceManager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ export class InferenceManager extends Publisher<InferenceServer[]> implements Di
287287
// Subscribe to container status update
288288
const disposable = this.containerRegistry.subscribe(containerId, (status: string) => {
289289
switch (status) {
290+
case 'die':
291+
this.updateServerStatus(engineId, containerId);
292+
clearInterval(intervalId);
293+
break;
290294
case 'remove':
291295
// Update the list of servers
292296
this.removeInferenceServer(containerId);

0 commit comments

Comments
 (0)