Part 5 of Goose, then any language on Flisk. Part 4 already proved the container. This part uses the function from part 2 on a second path. Flisk's command does not change. docs/byo.md still only requires PORT, 0.0.0.0, and HTTP 200 on /health.
0*0 + 1*1 + 2*2 + 3*3 + 4*4 is 30. That number should come from total, not from a literal in C.
Host check, before Docker
Keep shop.goose from part 3 and run it on the host. It exits. The server file must not.
goose shop.goose
You want the array [0, 1, 4, 9, 16] and the sum 30. If that is wrong, fix the function here. Do not debug it through Traefik.
server.goose
serve now takes the sum. i32 is enough for 30, and it matches the port as i32 call you already have.
fn total(xs: i64[:]) -> i64 {
var t = 0;
for x in xs { t += x; }
return t;
}
fn main() {
var grow: i64[>..] = [];
for i in 5 { grow.push(i * i); }
let sum = total(grow);
print(grow);
print(sum);
var text: u8[>..] = [];
let found = os.env("PORT", text);
let port, parsed = parse_int(text);
if !found || !parsed || port <= 0 || port > 65535 {
abort("PORT missing or not a port");
}
let code = serve(port as i32, sum as i32);
if code != 0 { abort("serve failed"); }
}
extern fn serve(port: i32, sum: i32) -> i32;
print still runs once, before accept. Look for 30 in the container log. If the log says 30 and /total says something else, the bug is in http.c, not in Goose.
http.c
/health stays the Flisk probe. /total is the extra path. The prefix is stripped, so the process never sees /api/goose/total.
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int serve(int port, int sum) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) return 1;
int on = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) return 2;
if (listen(fd, 16) != 0) return 3;
for (;;) {
int client = accept(fd, 0, 0);
if (client < 0) continue;
char req[1024];
int n = (int)read(client, req, sizeof(req) - 1);
if (n < 0) n = 0;
req[n] = 0;
char body;
int is_health = strncmp(req, "GET /health", 11) == 0;
int is_total = strncmp(req, "GET /total", 10) == 0;
if (is_health) {
snprintf(body, sizeof(body), "{\"status\":\"ok\"}\n");
} else if (is_total) {
snprintf(body, sizeof(body), "{\"total\":%d}\n", sum);
}
char resp;
if (is_health || is_total) {
snprintf(resp, sizeof(resp),
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: %zu\r\nConnection: close\r\n\r\n%s",
strlen(body), body);
} else {
const char *missing = "not found\n";
snprintf(resp, sizeof(resp),
"HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: %zu\r\nConnection: close\r\n\r\n%s",
strlen(missing), missing);
}
(void)write(client, resp, strlen(resp));
close(client);
}
}
Do not register the resource again. service.json did not change. There is no live reload for this type, so the new binary is a new image.
cd services/shop/goose-api
docker build -t goose-health .
docker run --rm -d --name goose-health -e PORT=4000 -p 4000:4000 goose-health
curl -fsS http://127.0.0.1:4000/health
curl -fsS http://127.0.0.1:4000/total
docker logs goose-health
docker stop goose-health
Expect {"status":"ok"}, then {"total":30}. Then restart the stack you already registered:
flisk up shop
curl -fsS http://api.<project>.localhost/api/goose/health
curl -fsS http://api.<project>.localhost/api/goose/total
Use the host --dry-run printed in part 4. A 200 on /health with a 404 on /total means Traefik is fine and the old image is still running.
| Change | Touch this | Do not touch |
|---|---|---|
| New path |
server.goose, http.c, then rebuild |
service.json, unless the health path changed |
| Probe |
/health must stay 200 |
--restart no |
| Route | inside the container, /total
|
/api/goose/total in the C strncmp
|
| Next language | a different Dockerfile, same flisk resource flags |
--language goose |
Swap Fastify, Gin, or Java into that directory and the Flisk line from part 4 is still the line. Only the files behind CMD change.
Top comments (0)