feat: CPU/memory resource limits per app #165
Reference in New Issue
Block a user
Delete Branch "feature/cpu-memory-resource-limits"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Adds configurable Docker CPU and memory resource constraints per app, closes #72.
Changes
Database
007_add_resource_limits.sql: addscpu_limit(REAL, nullable) andmemory_limit(INTEGER in bytes, nullable) columns to theappstableModel (
internal/models/app.go)CPULimit(sql.NullFloat64) andMemoryLimit(sql.NullInt64) fields toAppstructDocker Client (
internal/docker/client.go)CPULimit(float64, CPU cores) andMemoryLimit(int64, bytes) toCreateContainerOptionscpuLimitToNanoCPUs()conversion helper andbuildResources()to constructcontainer.ResourcesbuildEnvSlice()andbuildMounts()helpers fromCreateContainerfor cleaner codeHostConfig.Resources(NanoCPUs / Memory)Deploy Service (
internal/service/deploy/deploy.go)buildContainerOptionsreadsCPULimitandMemoryLimitfrom the app and passes them toCreateContainerOptionsHandlers (
internal/handlers/app.go)HandleAppUpdatereads and validatescpu_limitandmemory_limitform fieldsparseOptionalFloat64()for CPU limit parsing (positive float or empty)parseOptionalMemoryBytes()for memory parsing with unit suffixes (k/m/g) or plain bytesoptionalNullString()andapplyResourceLimits()helpers to keep cyclomatic complexity in checkTemplates
app_edit.html: Added "Resource Limits" section with CPU limit (cores) and memory limit (with unit suffix) fieldstemplates.go: AddedformatMemoryBytestemplate function for display (converts bytes → human-readable like256m,1g)Tests
internal/docker/resource_limits_test.go: Tests forcpuLimitToNanoCPUsconversioninternal/handlers/resource_limits_test.go: Tests forparseOptionalFloat64andparseOptionalMemoryBytes(happy paths, edge cases, validation)internal/models/models_test.go: Tests for App model resource limit persistence (save/load, null defaults, clearing)internal/service/deploy/deploy_container_test.go: Tests for container options with/without resource limitstemplates/templates_test.go: Tests forformatMemoryBytesformattingREADME
Behavior
0.5= half a core,2= two cores). Converted to Docker NanoCPUs internally.256m,1g,512k). Stored as bytes in the database.closes #72
Review: PR #165 — feat: CPU/memory resource limits per app
Policy Compliance
No policy violations found.
@sha256:hash ✅.golangci.ymlnot modified ✅007_add_resource_limits.sql) follows the established numbered migration pattern already present onmain(002–006) ✅Requirements Checklist (issue #72)
cpu_limitandmemory_limitcolumns to apps tableapp_edit.htmlhas Resource Limits section with CPU and memory inputsCreateContainerOptionscarries limits →buildResources()→HostConfig.ResourcesTest Coverage
cpuLimitToNanoCPUs()internal/docker/resource_limits_test.go✅parseOptionalFloat64()internal/handlers/resource_limits_test.go✅parseOptionalMemoryBytes()internal/handlers/resource_limits_test.go✅formatMemoryBytes()templates/templates_test.go✅internal/models/models_test.go✅internal/service/deploy/deploy_container_test.go✅Build Result
docker build .— PASS (fmt-check, lint, test, compile all green)Rebase onto
main— clean, no conflicts. Build still passes after rebase.Code Quality Notes
buildEnvSlice(),buildMounts(),buildResources()helpers improves readability ofCreateContaineroptionalNullString()DRYs up repeated null-string handling inHandleAppUpdate1.5g) and case-insensitive suffixesErrInvalidMemoryFormatandErrNegativeValueare properly defined as package-level error variablesVerdict: PASS ✅
All issue requirements fully implemented. Tests cover every new code path. No policy violations. Build green.