Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
FROM node:20-slim
## ── Build stage ──────────────────────────────
FROM node:20-slim AS build

WORKDIR /app

# Copy package files
COPY package*.json ./
COPY package*.json tsconfig.json ./
RUN npm ci

COPY src/ ./src/
RUN npm run build

# Install dependencies
RUN npm ci --only=production
## ── Runtime stage ────────────────────────────
FROM node:20

# Copy built files
COPY dist/ ./dist/
WORKDIR /app

COPY package*.json ./
RUN npm ci --omit=dev

COPY --from=build /app/dist/ ./dist/

# Set environment variables (override at runtime)
ENV NODE_ENV=production

# Run the bot
# Cloud Run requires a listening port
EXPOSE 8080

CMD ["node", "dist/index.js", "start"]
12 changes: 11 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ import {
pathToPixels,
} from "./pathfinding.js";
import { resolveBotConfig, type BotConfig } from "./bot-config.js";
import { startHealthServer } from "./server.js";

// Resolve config from CLI args (--bot=clawd or --bot=gremlin)
// Resolve config from CLI args, BOT_NAME env var, or default to "clawd"
const config = resolveBotConfig();

/**
Expand Down Expand Up @@ -778,6 +779,15 @@ export default defineAgent({

// Run the agent when executed directly
if (process.argv[1] === fileURLToPath(import.meta.url)) {
// Start HTTP health-check server for Cloud Run (no-op locally if PORT unset).
startHealthServer();

// Graceful shutdown on SIGTERM (sent by Cloud Run before stopping a container).
process.on("SIGTERM", () => {
console.log("[Bot] SIGTERM received, shutting down gracefully...");
process.exit(0);
});

cli.runApp(
new WorkerOptions({
agent: fileURLToPath(import.meta.url),
Expand Down
21 changes: 21 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createServer } from "node:http";

/**
* Minimal HTTP health-check server for Cloud Run.
*
* Cloud Run requires a listening port to manage container lifecycle.
* This server responds 200 to all requests — used for both health checks
* and wake-up pings from the Cloud Function.
*/
export function startHealthServer(): void {
const port = parseInt(process.env.PORT || "8080", 10);

const server = createServer((_req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("ok");
});

server.listen(port, () => {
console.log(`[Health] Listening on port ${port}`);
});
}
Loading