Skip to content

Commit 9dfe492

Browse files
committed
fix: update container examples
Move container examples to /examples/container and update them
1 parent 004f039 commit 9dfe492

6 files changed

Lines changed: 113 additions & 39 deletions

File tree

crates/perry-container-compose/examples/multi-service/main.ts

Lines changed: 0 additions & 36 deletions
This file was deleted.

crates/perry-container-compose/examples/build/Containerfile renamed to examples/container/build/Containerfile

File renamed without changes.

crates/perry-container-compose/examples/build/main.ts renamed to examples/container/build/main.ts

File renamed without changes.

crates/perry-container-compose/examples/forgejo/main.ts renamed to examples/container/forgejo/main.ts

File renamed without changes.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* perry/compose — multi-service stack with named volumes + env interpolation
3+
*
4+
* Two services on a user-defined network:
5+
* - db : postgres with a named volume for durable state
6+
* - web : nginx pointing at the postgres host (cross-service DNS)
7+
*
8+
* Demonstrates:
9+
* - `${VAR:-default}` env interpolation (resolved at the FFI boundary
10+
* against process.env before the spec hits the engine)
11+
* - Named volume that survives `down(stack, { volumes: false })` and
12+
* is removed by `down(stack, { volumes: true })`
13+
* - User-defined network so cross-service DNS works (web → db:5432)
14+
* - `depends_on` for explicit startup ordering
15+
*
16+
* Run:
17+
* perry main.ts -o multi-service
18+
* ./multi-service # uses platform default
19+
* DB_PASSWORD=hunter2 ./multi-service # override interpolation
20+
* PERRY_CONTAINER_BACKEND=docker ./multi-service # pin runtime
21+
*
22+
* Note: the small `setTimeout` calls between FFI awaits keep the
23+
* runtime event loop alive while tokio tasks settle the Promises —
24+
* see examples/container/simple/main.ts for the why.
25+
*/
26+
27+
import { up, down, logs } from 'perry/compose';
28+
import { getBackend } from 'perry/container';
29+
30+
async function main() {
31+
console.log('backend:', getBackend());
32+
console.log('starting db + web stack...');
33+
34+
const stack = await up({
35+
version: '3.8',
36+
services: {
37+
db: {
38+
image: 'postgres:16-alpine',
39+
container_name: 'perry-example-multi-db',
40+
environment: {
41+
POSTGRES_USER: '${DB_USER:-myuser}',
42+
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}',
43+
POSTGRES_DB: 'mydb',
44+
},
45+
volumes: ['db-data:/var/lib/postgresql/data'],
46+
ports: ['15432:5432'],
47+
networks: ['app-net'],
48+
},
49+
web: {
50+
// Public-image stand-in for "your app." Real apps swap this
51+
// for their own image; the rest of the spec stays the same.
52+
image: 'nginx:alpine',
53+
container_name: 'perry-example-multi-web',
54+
depends_on: ['db'],
55+
ports: ['13000:80'],
56+
environment: {
57+
DATABASE_URL: 'postgres://${DB_USER:-myuser}:${DB_PASSWORD:-secret}@db:5432/mydb',
58+
},
59+
networks: ['app-net'],
60+
},
61+
},
62+
networks: {
63+
'app-net': { driver: 'bridge' },
64+
},
65+
volumes: {
66+
// Empty `{}` here would trip a Perry runtime auto-stringification
67+
// bug; use any non-empty config instead. The default driver on
68+
// every backend is "local" — declaring it explicitly makes the
69+
// spec robust.
70+
'db-data': { driver: 'local' },
71+
},
72+
});
73+
console.log('stack handle:', String(stack));
74+
75+
// Keep loop alive while up's tokio task settles.
76+
await new Promise((r) => setTimeout(r, 1000));
77+
78+
// Drain logs from both services.
79+
const logsJson = await logs(stack, { tail: 5 });
80+
console.log('logs (last 5 lines):');
81+
const parsed = JSON.parse(logsJson);
82+
console.log(' stdout (head):', parsed.stdout.slice(0, 200));
83+
84+
await new Promise((r) => setTimeout(r, 200));
85+
console.log('tearing down (and dropping the db-data volume)...');
86+
await down(stack, { volumes: true });
87+
console.log('done');
88+
console.log('PASS');
89+
}
90+
91+
main().catch((err) => {
92+
console.error('FAIL:', err);
93+
process.exit(1);
94+
});

crates/perry-container-compose/examples/simple/main.ts renamed to examples/container/simple/main.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,38 @@
88
* perry main.ts -o simple
99
* ./simple # uses platform default
1010
* PERRY_CONTAINER_BACKEND=docker ./simple # pin a specific runtime
11+
*
12+
* Note on the `setTimeout` calls below: Perry's runtime currently
13+
* doesn't keep the event loop alive purely on a pending FFI Promise,
14+
* so a small `setTimeout` after each container op gives the tokio
15+
* task time to complete before the next `await`. Without it, `up()`
16+
* silently exits before the container is created. This is a Perry
17+
* runtime issue (tracked separately); every working compose example
18+
* uses the same workaround.
1119
*/
1220

1321
import { up, down, ps } from 'perry/compose';
1422
import { getBackend } from 'perry/container';
1523

1624
async function main() {
17-
console.log(`backend: ${getBackend()}`);
25+
console.log('backend:', getBackend());
26+
console.log('starting stack...');
1827

1928
const stack = await up({
29+
version: '3.8',
2030
services: {
2131
web: {
2232
image: 'nginx:alpine',
2333
container_name: 'perry-example-simple-nginx',
2434
ports: ['18080:80'],
25-
labels: { app: 'simple-nginx' },
2635
},
2736
},
2837
});
29-
console.log(`stack handle: ${String(stack)}`);
38+
console.log('stack handle:', String(stack));
39+
40+
// Keep the runtime alive long enough for `up`'s tokio task to
41+
// settle the Promise (see header note).
42+
await new Promise((r) => setTimeout(r, 500));
3043

3144
// ps returns a JSON-encoded ContainerInfo[] — parse it.
3245
const statuses = JSON.parse(await ps(stack));
@@ -35,8 +48,11 @@ async function main() {
3548
console.log(` ${s.name}\t${s.status}`);
3649
}
3750

51+
await new Promise((r) => setTimeout(r, 200));
52+
console.log('tearing down...');
3853
await down(stack, { volumes: false });
3954
console.log('done');
55+
console.log('PASS');
4056
}
4157

4258
main().catch((err) => {

0 commit comments

Comments
 (0)