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
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ pnpm dev:coder-acp-copilot # A single worker natively (pnpm dev:<service-
pnpm open:portal # Open the portal in your browser
```

The first Docker start compiles the Rust AI gateway inside its development
container and can take several minutes. During development, the gateway may use
all CPUs assigned to Docker or the Podman VM, while its memory remains limited
to 2 GiB. Keep the Compose command running until the `coder-acp-copilot` logs
show that it connected to MongoDB and ensured `queue-coder-acp-copilot`; runs
submitted before that worker is ready remain pending. Later starts reuse the
gateway's named Cargo target volume and are faster.

### Debug the Docker development API

`pnpm docker:dev:portal` starts the API with the Node inspector enabled. To
Expand Down
18 changes: 9 additions & 9 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,23 +245,23 @@ services:
build:
target: dev
# The dev stage compiles the Rust gateway in-container via `cargo watch`.
# A cold `cargo build` peaks well above the prod 512m runtime cap and would
# thrash/OOM at that limit (rustc stalls near the cap at ~2% CPU), so give it
# headroom — mirrors the 1g dev bump the other in-container-compiled services
# (api, judge, portal, ...) already get.
# Do not inherit the production 0.5 CPU / 512m runtime caps: a cold build can
# otherwise outlive the health window and prevent dependent workers from
# starting. Let rustc use all CPUs assigned to the container runtime or
# Podman VM while keeping memory bounded.
cpus: !reset null
mem_limit: 2g
# Persist the cargo `target/` cache in a named volume so the cold build only
# happens once and survives container recreation. Re-declare the base
# `gateway_cert` mount so this list fully specifies the dev mounts.
volumes:
- gateway_cert:/certs
- gateway_target:/build/target
# A cold cargo build takes several minutes on the very first run (empty cache,
# throttled to the base `cpus: 0.5`); the base `start_period: 120s` is enough
# once the target/ cache volume is populated but not on a fresh volume. Bump
# it for the dev profile only.
# A cold cargo build takes several minutes on the first run with an empty
# target cache. Keep a generous dev-only grace period for slower machines;
# subsequent starts reuse the named target volume and become healthy sooner.
healthcheck:
start_period: 360s
start_period: 600s
develop:
watch:
- action: sync
Expand Down
11 changes: 10 additions & 1 deletion docs/architecture/ai-gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -466,9 +466,18 @@ gateway:
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:18000/health"]
interval: 5s
retries: 10
retries: 12
```

The development override compiles the gateway under `cargo watch`, persists
`/build/target` in the `gateway_target` named volume, removes the production CPU
quota so compilation may use all CPUs assigned to the container runtime or
Podman VM, and raises the memory limit to 2 GiB. Its health check has a
600-second first-start grace period so a cold Cargo build cannot cause Compose
to abandon dependent workers. The Copilot worker waits for the gateway to
become healthy; until the worker connects to `queue-coder-acp-copilot`,
submitted runs remain pending.

Workers connect via `HTTP_PROXY=http://<sessionId>@gateway:18000` (session ID embedded as userinfo) and `DEV_PROXY_API_URL=http://gateway:18000`.

## Kubernetes Deployment
Expand Down
80 changes: 80 additions & 0 deletions scripts/docker-compose.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { spawnSync } from "node:child_process";
import { describe, expect, it } from "vitest";

interface ComposeService {
cpus?: number;
depends_on?: Record<string, { condition: string }>;
healthcheck?: {
test?: string[];
start_period?: string;
};
mem_limit?: string;
volumes?: Array<{
source?: string;
target: string;
}>;
}

interface ComposeConfig {
services: Record<string, ComposeService>;
}

// Keep the default unit suite runnable without Docker while preserving strict
// merged-configuration validation whenever Compose is available.
const dockerComposeAvailable =
spawnSync("docker", ["compose", "version"], {
encoding: "utf8",
}).status === 0;

describe("development Docker Compose configuration", () => {
it.skipIf(!dockerComposeAvailable)(
"keeps the gateway cold-build resources and Copilot worker dependency",
() => {
const result = spawnSync(
"docker",
[
"compose",
"-f",
"docker-compose.yml",
"-f",
"docker-compose.dev.yml",
"--profile",
"copilot",
"config",
"--format",
"json",
],
{
encoding: "utf8",
env: { ...process.env, GITHUB_TOKEN: process.env.GITHUB_TOKEN ?? "" },
},
);

expect(result.status, result.stderr).toBe(0);

const config = JSON.parse(result.stdout) as ComposeConfig;
const gateway = config.services.gateway;
const copilotWorker = config.services["coder-acp-copilot"];

expect(gateway.cpus).toBeUndefined();
expect(gateway.mem_limit).toBe(String(2 * 1024 ** 3));
expect(gateway.healthcheck?.start_period).toBe("10m0s");
expect(gateway.healthcheck?.test).toEqual([
"CMD-SHELL",
"wget -qO- http://127.0.0.1:18000/health || exit 1",
]);
expect(gateway.volumes).toContainEqual(
expect.objectContaining({
source: "gateway_target",
target: "/build/target",
}),
);
expect(copilotWorker.depends_on?.gateway?.condition).toBe(
"service_healthy",
);
},
);
});
4 changes: 3 additions & 1 deletion website/src/styles/contributions.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*
*/

/*
* Shared presentation for website contribution data: status messages,
* count pills, cards, and development-only sample labels.
*/
Expand Down
4 changes: 3 additions & 1 deletion website/src/styles/contributors.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*
*/

/*
* Contributors (<scope-contributors>). An avatar wall on the
* landing page and a card grid on the Community > Contribute page. Shares
* the card, message and sample-tag styles in contributions.css.
Expand Down
Loading