Fix race condition in subscription cleanup and add log size limit for memory management
Co-authored-by: ajnart <49837342+ajnart@users.noreply.github.com>
This commit is contained in:
1 parent
8b7d849cd0
commit
58a2c508c6
2 files changed
+51
-28
No files matched your search
@@ -142,37 +142,47 @@ export const dockerRouter = createTRPCRouter({
|
||||
)
|
||||
.subscription(({ input }) => {
|
||||
return observable<string>((emit) => {
|
||||
let cleanup: (() => void) | undefined;
|
||||
let cleanupFn: (() => void) | undefined;
|
||||
let isSubscribed = true;
|
||||
|
||||
streamContainerLogsAsync(
|
||||
input.id,
|
||||
input.tail ?? 200,
|
||||
(data) => {
|
||||
emit.next(data);
|
||||
},
|
||||
(err) => {
|
||||
emit.error(
|
||||
new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: err.message,
|
||||
}),
|
||||
const initializeStream = async () => {
|
||||
try {
|
||||
cleanupFn = await streamContainerLogsAsync(
|
||||
input.id,
|
||||
input.tail ?? 200,
|
||||
(data) => {
|
||||
if (isSubscribed) {
|
||||
emit.next(data);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (isSubscribed) {
|
||||
emit.error(
|
||||
new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: err.message,
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
.then((cleanupFn) => {
|
||||
cleanup = cleanupFn;
|
||||
})
|
||||
.catch((err) => {
|
||||
emit.error(
|
||||
new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: err instanceof Error ? err.message : "Container not found",
|
||||
}),
|
||||
);
|
||||
});
|
||||
} catch (err) {
|
||||
if (isSubscribed) {
|
||||
emit.error(
|
||||
new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: err instanceof Error ? err.message : "Container not found",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void initializeStream();
|
||||
|
||||
return () => {
|
||||
cleanup?.();
|
||||
isSubscribed = false;
|
||||
cleanupFn?.();
|
||||
};
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -38,12 +38,25 @@ export const DockerLogsModal = createModal<DockerLogsModalInnerProps>(({ innerPr
|
||||
},
|
||||
);
|
||||
|
||||
// Maximum log size to prevent memory issues (500KB)
|
||||
const MAX_LOG_SIZE = 500 * 1024;
|
||||
|
||||
// Subscribe to streaming logs
|
||||
clientApi.docker.subscribeLogs.useSubscription(
|
||||
{ id: innerProps.id, tail: innerProps.tail ?? 200 },
|
||||
{
|
||||
onData(data) {
|
||||
setLogs((prev) => prev + data);
|
||||
setLogs((prev) => {
|
||||
const newLogs = prev + data;
|
||||
// Truncate from the beginning if logs exceed maximum size
|
||||
if (newLogs.length > MAX_LOG_SIZE) {
|
||||
const truncated = newLogs.slice(-MAX_LOG_SIZE);
|
||||
// Try to start from a newline to avoid partial lines
|
||||
const firstNewline = truncated.indexOf("\n");
|
||||
return firstNewline > 0 ? truncated.slice(firstNewline + 1) : truncated;
|
||||
}
|
||||
return newLogs;
|
||||
});
|
||||
setIsLoading(false);
|
||||
},
|
||||
onError(err) {
|
||||
|
||||
Reference in new issue
Block a user