gombit

command
v0.1.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 5, 2026 License: MIT Imports: 13 Imported by: 0

README

gombit

The BENCH-1 Gombit-runtime implementation of the canonical /api/projects CRUD API (issue #141, ../../docs/schema.md): a normal Gombit app — Huma handlers (internal/project), GORM, framework.App — using Gombit's normal public APIs unmodified, run in production mode. Compared against ../gin-gorm, the primary framework-tax control implementing the same API without Gombit.

Migrations

Unlike gin-gorm (GORM AutoMigrate, its own idiomatic mechanism), this app uses Gombit's real migration path — Atlas, via gombit db makemigrations/ migrate (AGENTS.md D3: never AutoMigrate for a real Gombit app). The generated migration is committed under database/migrations/ like any real Gombit app's would be; regenerate it only if the models change:

cd benchmarks/apps/gombit
go run github.com/gombit-dev/gombit/cmd/gombit db makemigrations create_projects \
  --driver postgres \
  --model github.com/gombit-dev/gombit/benchmarks/apps/gombit/internal/project.User \
  --model github.com/gombit-dev/gombit/benchmarks/apps/gombit/internal/project.Project

Run

docker compose -f benchmarks/compose.yml up -d postgres

# create a database separate from gin-gorm's (see benchmarks/apps/gin-gorm/README.md
# for why AutoMigrate and Atlas schemas shouldn't share a database) and migrate — once
createdb -h 127.0.0.1 -p 55432 -U gombit gombit_bench_gombit
cd benchmarks/apps/gombit
GOMBIT_DATABASE_DRIVER=postgres \
GOMBIT_DATABASE_DSN="postgres://gombit:gombit@127.0.0.1:55432/gombit_bench_gombit?sslmode=disable" \
  go run github.com/gombit-dev/gombit/cmd/gombit db migrate

# seed (1,000 users, 100,000 projects) — idempotent, truncates first
go run . -seed

# serve
go run .

Env vars (all optional, defaults match benchmarks/compose.yml):

Var Default
DATABASE_URL postgres://gombit:gombit@127.0.0.1:55432/gombit_bench_gombit?sslmode=disable
PORT 8080
POOL_MAX_OPEN 20 issue #141 "Connection pooling" pins this to 20 across every implementation
POOL_MAX_IDLE 20

cfg.API.Prefix is set to /api in main.go, overriding Gombit's own /api/v1 default — the canonical route spec and gin-gorm both use /api with no version segment; left at the framework default this app's own route surface wouldn't have matched its own control.

Under compose (containerized, with the §7 resource budget)

The app is containerized (Dockerfile, built from the repo root) and wired into benchmarks/compose.yml with the §7 app ceiling (2 vCPU / 1 GiB). Because it applies real Atlas migrations (not AutoMigrate), the image also carries the gombit CLI and the pinned atlas binary (ATLAS_IMAGE in benchmarks/config/versions.env, the -alpine variant so the binary matches the runtime base), plus a psql client, and its entrypoint has three verbs — migrate, seed, serve. serve does not migrate, so run them in order. The gombit_bench_gombit database is created by the migrate verb if absent (idempotent, every bring-up — not by a fresh-volume init script, which wouldn't fire on this suite's already-initialized Postgres volume):

docker compose --env-file benchmarks/config/versions.env \
  -f benchmarks/compose.yml up -d postgres

# apply migrations (also creates gombit_bench_gombit if missing), then seed
docker compose --env-file benchmarks/config/versions.env \
  -f benchmarks/compose.yml run --rm gombit migrate
docker compose --env-file benchmarks/config/versions.env \
  -f benchmarks/compose.yml run --rm gombit seed

# now serve, and confirm the §7 ceiling actually landed on the live container
docker compose --env-file benchmarks/config/versions.env \
  -f benchmarks/compose.yml up -d gombit
go run ./benchmarks/scripts/inspect-limits \
  -container "$(docker compose -f benchmarks/compose.yml ps -q gombit)" \
  -cpus 2 -memory 1g

make benchmark-crud-all brings all six apps up and runs run-crud over each; this containerizes the second of the two Go apps on the same pattern as gin-gorm.

Test

# pure unit tests — none of this package's own; the seed formulas it shares
# with gin-gorm are tested in benchmarks/apps/shared

# per-app integration suite, needs a live, already-migrated PostgreSQL
# instance. -p 1 is required, not cosmetic: this expands to two packages
# (this one and internal/project), each its own test binary, and both
# TRUNCATE the same tables on every test's setup. Without -p 1, go test
# runs those binaries in parallel (bounded by GOMAXPROCS) and one's
# TRUNCATE can land mid-assertion in the other.
go test -tags integration -p 1 ./benchmarks/apps/gombit/... \
  -database.dsn "postgres://gombit:gombit@127.0.0.1:55432/gombit_bench_gombit?sslmode=disable"

# cross-implementation fairness check: builds and runs both real binaries,
# needs both databases already seeded (`-seed` on each app) — heavier than
# the per-app suite, so it isn't wired into routine PR CI yet (see
# docs/plans/BENCH-1-benchmark-suite.md Phase 3b); run it locally:
go test -tags integration ./benchmarks/apps/ -run TestCrossImplementationFairness \
  -gin-gorm.dsn "postgres://gombit:gombit@127.0.0.1:55432/gombit_bench?sslmode=disable" \
  -gombit.dsn "postgres://gombit:gombit@127.0.0.1:55432/gombit_bench_gombit?sslmode=disable"

CI runs the per-app suite in .github/workflows/ci.yml's database-postgres job, against a third database (gombit_bench_gombit) separate from both gombit (auth/database/admin) and gombit_bench (gin-gorm) — this app's users/projects tables come from a real Atlas migration, not AutoMigrate, so they shouldn't share a database with either.

Covers the same contract gin-gorm's suite does — full CRUD round trip, blank-name rejection on both create and update, pagination/ordering, and the 3-query / 2-query (empty page) N+1 guard — plus one difference documented below.

A discovered framework gap — fixed (issue #202)

POST /api/projects with a nonexistent owner_id used to return 500 internal instead of a 4xx client error. This app uses Gombit's normal database.MapPersistError (github.com/gombit-dev/gombit/database) unmodified, and that function only special-cased unique-constraint violations — a foreign-key violation fell through to internal. gin-gorm's control implementation doesn't use that framework helper (see its README) and already mapped the same input to 422, so the two implementations disagreed on equivalent input.

This was deliberately not patched here while it was open: issue #141 requires using Gombit's normal public APIs as-is ("do not bypass ... normal Gombit response handling"), and the entire point of this app is measuring what a real Gombit user gets. TestCreateInvalidOwnerIDReturnsValidationError (renamed from ...ReturnsInternalError) used to pin the gap so a framework fix would show up here as an expected test change rather than a mysterious fairness-check failure; see docs/plans/BENCH-1-benchmark-suite.md Phase 3b for that original writeup. database.MapPersistError was fixed in issue #202 (foreign-key and NOT NULL violations now map to a D10 validation error), so this app now gets the same 422 as gin-gorm through Gombit's normal public APIs, unmodified — no special-casing needed.

Status

Implementation, migration, and both test suites are done and verified against real PostgreSQL (schema diffed statement-log-for-statement-log against gin-gorm's N+1 behavior, and cross-checked live via TestCrossImplementationFairness). Both Go apps now have benchmarks/compose.yml services with the §7 budget (see Under compose above). Still open (tracked in docs/plans/BENCH-1-benchmark-suite.md Phase 3b/6): wiring the cross-implementation fairness check into CI (needs a lighter seed-size mechanism than the canonical 1,000/100,000, which is Phase 8's concern), the last ecosystem app's compose service (nestjs; django/rails/laravel are in), and the six-app bring-up/run-crud loop.

Documentation

Overview

Command gombit is the BENCH-1 Gombit-runtime implementation of the canonical /api/projects CRUD API (issue #141, benchmarks/docs/schema.md): a normal Gombit app — Huma handlers, GORM, framework.App — using Atlas migrations (`gombit db makemigrations`/`migrate`, not AutoMigrate; AGENTS.md D3) applied as a separate step before this binary runs, the same way a deployed Gombit app would. See benchmarks/apps/gombit/database/migrations/ and this directory's README for exact commands.

Directories

Path Synopsis
internal
project
Package project implements the canonical /api/projects CRUD API (benchmarks/docs/schema.md) as a normal Gombit feature package: Huma handlers, GORM models, framework.App wiring — the same shape `gombit make resource` would emit, hand-extended with the update/delete and pagination the generator doesn't produce yet.
Package project implements the canonical /api/projects CRUD API (benchmarks/docs/schema.md) as a normal Gombit feature package: Huma handlers, GORM models, framework.App wiring — the same shape `gombit make resource` would emit, hand-extended with the update/delete and pagination the generator doesn't produce yet.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL