Skip to content

Commit f02fe1f

Browse files
perf: optimize container status checking by batching per server
- Group containers by server and make one pct list call per server - Replace individual container checks with batch processing - Parse all container statuses from single pct list response per server - Add proper TypeScript safety checks for undefined values - Significantly reduce SSH calls from N containers to 1 call per server This should dramatically speed up status loading for multiple containers on the same server
1 parent b39d85f commit f02fe1f

File tree

1 file changed

+50
-17
lines changed

1 file changed

+50
-17
lines changed

src/server/api/routers/installedScripts.ts

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ async function getLocalContainerStatuses(containerIds: string[]): Promise<Record
2323
const vmid = parts[0];
2424
const status = parts[1];
2525

26-
if (containerIds.includes(vmid)) {
26+
if (vmid && containerIds.includes(vmid)) {
2727
statusMap[vmid] = status === 'running' ? 'running' : 'stopped';
2828
}
2929
}
@@ -48,38 +48,47 @@ async function getLocalContainerStatuses(containerIds: string[]): Promise<Record
4848
}
4949
}
5050

51-
// Helper function to check remote container status
52-
async function getRemoteContainerStatus(containerId: string, server: any): Promise<'running' | 'stopped' | 'unknown'> {
51+
// Helper function to check remote container statuses (multiple containers per server)
52+
async function getRemoteContainerStatuses(containerIds: string[], server: any): Promise<Record<string, 'running' | 'stopped' | 'unknown'>> {
5353
return new Promise((resolve) => {
5454
const sshService = getSSHExecutionService();
55+
const statusMap: Record<string, 'running' | 'stopped' | 'unknown'> = {};
56+
57+
// Initialize all containers as unknown
58+
for (const containerId of containerIds) {
59+
statusMap[containerId] = 'unknown';
60+
}
5561

5662
sshService.executeCommand(
5763
server,
5864
'pct list',
5965
(data: string) => {
60-
// Parse the output to find the specific container
66+
// Parse the output to find all containers
6167
const lines = data.trim().split('\n');
6268
const dataLines = lines.slice(1); // Skip header
6369

6470
for (const line of dataLines) {
6571
const parts = line.trim().split(/\s+/);
66-
if (parts.length >= 2 && parts[0] === containerId) {
72+
if (parts.length >= 2) {
73+
const vmid = parts[0];
6774
const status = parts[1];
68-
resolve(status === 'running' ? 'running' : 'stopped');
69-
return;
75+
76+
// Check if this is one of the containers we're looking for
77+
if (vmid && containerIds.includes(vmid)) {
78+
statusMap[vmid] = status === 'running' ? 'running' : 'stopped';
79+
}
7080
}
7181
}
7282

73-
// Container not found in the list
74-
resolve('unknown');
83+
resolve(statusMap);
7584
},
7685
(error: string) => {
77-
console.error(`Error checking remote container ${containerId}:`, error);
78-
resolve('unknown');
86+
console.error(`Error checking remote containers on server ${server.name}:`, error);
87+
resolve(statusMap); // Return the map with unknown statuses
7988
},
8089
(exitCode: number) => {
8190
if (exitCode !== 0) {
82-
resolve('unknown');
91+
resolve(statusMap); // Return the map with unknown statuses
8392
}
8493
}
8594
);
@@ -668,14 +677,38 @@ export const installedScriptsRouter = createTRPCRouter({
668677
Object.assign(statusMap, localStatuses);
669678
}
670679

671-
// Check remote containers
680+
// Check remote containers - group by server and make one call per server
681+
const serverGroups: Record<string, Array<{containerId: string, server: any}>> = {};
682+
672683
for (const { containerId, server } of remoteContainers) {
684+
const serverKey = `${server.id}-${server.name}`;
685+
if (!serverGroups[serverKey]) {
686+
serverGroups[serverKey] = [];
687+
}
688+
serverGroups[serverKey].push({ containerId, server });
689+
}
690+
691+
// Make one call per server
692+
for (const [serverKey, containers] of Object.entries(serverGroups)) {
673693
try {
674-
const remoteStatus = await getRemoteContainerStatus(containerId, server);
675-
statusMap[containerId] = remoteStatus;
694+
if (containers.length === 0) continue;
695+
696+
const server = containers[0]?.server;
697+
if (!server) continue;
698+
699+
const containerIds = containers.map(c => c.containerId).filter(Boolean);
700+
const serverStatuses = await getRemoteContainerStatuses(containerIds, server);
701+
702+
// Merge the results
703+
Object.assign(statusMap, serverStatuses);
676704
} catch (error) {
677-
console.error(`Error checking status for container ${containerId} on server ${server.name}:`, error);
678-
statusMap[containerId] = 'unknown';
705+
console.error(`Error checking statuses for server ${serverKey}:`, error);
706+
// Set all containers for this server to unknown
707+
for (const container of containers) {
708+
if (container.containerId) {
709+
statusMap[container.containerId] = 'unknown';
710+
}
711+
}
679712
}
680713
}
681714

0 commit comments

Comments
 (0)