Merge branch 'claude/practical-ramanujan-f8158d' into dev

feat: block function execution while container is initializing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Space-Banane
2026-07-07 21:06:51 +02:00
2 changed files with 62 additions and 26 deletions
+61 -25
View File
@@ -94,6 +94,25 @@ async function getRuntimeEnvironment(functionData: Pick<Function, "env" | "userI
);
}
async function isContainerReady(container: Docker.Container, since: number): Promise<boolean> {
try {
const stream = await container.logs({
stdout: true,
stderr: false,
follow: false,
since,
}) as NodeJS.ReadableStream;
return new Promise<boolean>((resolve) => {
let data = "";
stream.on("data", (chunk: Buffer) => { data += chunk.toString("utf8"); });
stream.on("end", () => { resolve(data.includes("[SHSF] Container ready.")); });
stream.on("error", () => resolve(false));
});
} catch {
return false;
}
}
export async function persistFunctionExecutionLog(
input: PersistedFunctionExecutionLogInput,
) {
@@ -240,6 +259,7 @@ export async function executeFunction(
let initScript =
"#!/bin/sh\nset -e\necho '[SHSF INIT] Starting environment setup...'\ncd /app\n";
let containerNotReady = false;
try {
let container = docker.getContainer(containerName);
@@ -482,7 +502,21 @@ export async function executeFunction(
}
}
// At this point, container is running (either existing or newly created and initialized)
// Block execution if the container has not yet finished initializing (init.sh still running)
const containerInspect = await container.inspect();
const containerStartedAt = new Date(containerInspect.State.StartedAt).getTime() / 1000;
if (!await isContainerReady(container, containerStartedAt)) {
log.warn({ functionId: id }, "Container not ready — blocking execution");
containerNotReady = true;
return {
logs: "Function is not ready yet.",
result: { _shsf: "v2" as const, _code: 503, _res: "Function is not ready yet." },
tooks: [{ description: "Container not ready", value: (Date.now() - starting_time) / 1000, timestamp: Date.now() }],
exit_code: -10,
};
}
// At this point, container is running and ready (init completed)
// Now, execute the function logic using docker exec
await fs.writeFile(transportPaths.payloadPath, payload);
@@ -715,31 +749,33 @@ export async function executeFunction(
totalSeconds: ((Date.now() - starting_time) / 1000).toFixed(3),
}, "Function execution complete");
try {
await prisma.function.update({
where: { id },
data: { lastRun: new Date() },
});
} catch (dbError) {
log.error({ err: dbError }, "Error updating function lastRun");
}
if (!containerNotReady) {
try {
await prisma.function.update({
where: { id },
data: { lastRun: new Date() },
});
} catch (dbError) {
log.error({ err: dbError }, "Error updating function lastRun");
}
try {
await persistFunctionExecutionLog({
functionId: id,
functionData,
logs,
output:
typeof func_result === "string" && func_result !== ""
? func_result
: JSON.stringify(null),
payload,
exit_code: exitCode,
tooks,
...(options?.ratelimit ? { ratelimit: options.ratelimit } : {}),
});
} catch (error) {
log.error({ err: error }, "Error creating trigger log");
try {
await persistFunctionExecutionLog({
functionId: id,
functionData,
logs,
output:
typeof func_result === "string" && func_result !== ""
? func_result
: JSON.stringify(null),
payload,
exit_code: exitCode,
tooks,
...(options?.ratelimit ? { ratelimit: options.ratelimit } : {}),
});
} catch (error) {
log.error({ err: error }, "Error creating trigger log");
}
}
}
}
+1 -1
View File
@@ -30,7 +30,7 @@
## P3 - Priority 3 (Low)
- [x] Account Wide Environment Variables
- [ ] Add a way to manage function dependencies (eg. requirements.txt) from the UI
- [ ] Runner & Backend: Implement a Block for interactions on Functions while "Container ready." not reached (pretty much wait for “[SHSF] Container ready.”). Message would be something like "Function is not ready yet."
- [x] Runner & Backend: Implement a Block for interactions on Functions while Container ready. not reached (pretty much wait for “[SHSF] Container ready.”). Message would be something like Function is not ready yet.
- [ ] Function Logs Update
- Investigate (Shows only Errors)
- Hide Specifics (regex blur)