120 lines
6.8 KiB
YAML
120 lines
6.8 KiB
YAML
services:
|
|
neo4j:
|
|
image: neo4j:5
|
|
container_name: agenticcode-neo4j
|
|
ports:
|
|
- "7474:7474"
|
|
- "7687:7687"
|
|
environment:
|
|
NEO4J_AUTH: neo4j/agenticcode
|
|
# Memory caps. Without them the JVM sizes its heap ergonomically at 25% of host RAM
|
|
# (~7.8 GiB here) and never gives it back: measured 6.17 GiB still held one hour after a
|
|
# deep refresh of upms had finished, at <1% CPU. The cap is what forces the JVM to
|
|
# collect rather than commit.
|
|
# 2G -> 4G (2026-09-23): a deep ingest of upms2 (6311 Natural files) failed at batch 1601-1800
|
|
# with "allocation of an extra 34.2 MiB would use more than the limit 1.4 GiB ...
|
|
# dbms.memory.transaction.total.max threshold reached". That limit defaults to 70% of the heap,
|
|
# and one 200-file persist transaction now writes ~64k nodes / ~159k relationships (item 160
|
|
# positional nodes, copycode copies), which no longer fits in 1.4 GiB. 4G lifts the ceiling to
|
|
# 2.8 GiB. The idle-heap concern above still holds: G1PeriodicGCInterval returns it.
|
|
NEO4J_server_memory_heap_max__size: "4G"
|
|
NEO4J_server_memory_heap_initial__size: "512M"
|
|
# 512M -> 1G -> 3G -> 2G. The store has grown to 2.4 GB (1.2 GB of it range indexes), so 1G
|
|
# covered only ~42% of it. 2G covers nearly all of it; the 2.5 GB of transaction logs are
|
|
# deliberately not counted, Neo4j does not keep them here. Both sizes were measured on a deep
|
|
# refresh of upms: 1G = 552 s, 3G = 519 s, 2G = 517 s. The whole gain is already had at 2G, so
|
|
# the third gigabyte stays with the host (a 4 GB VirtualBox guest runs alongside).
|
|
#
|
|
# The gain is ~6% and modest on purpose to record why: `directio` is false, so Neo4j reads
|
|
# through the OS file cache and the store is cached twice. Block I/O across two whole refresh
|
|
# runs was 237 MB read against a 2.4 GB store — there was never disk I/O to save. A cache miss
|
|
# costs a read() syscall plus a copy, not a seek, and 6% is what removing those is worth. On a
|
|
# host whose file cache could NOT hold the store, the same setting would matter far more — so
|
|
# treat these numbers as this machine's data points, not as a recommendation.
|
|
# Community Edition cannot pre-warm the cache: the first refresh after a restart runs cold
|
|
# (540 s here) and is not a fair measurement.
|
|
NEO4J_server_memory_pagecache_size: "2G"
|
|
# Return committed-but-unused heap to the OS while idle instead of sitting on it. Without this
|
|
# the JVM held everything it had ever needed: 6.17 GiB an hour after a refresh had finished.
|
|
NEO4J_server_jvm_additional: "-XX:G1PeriodicGCInterval=300000"
|
|
# Hard ceiling: heap 2G + pagecache 2G + metaspace, direct buffers and GC overhead.
|
|
# Raised 4g -> 5g after a verification run peaked at exactly 4096 of 4096 MB — no OOM-kill, but
|
|
# zero reserve. An OOM-kill mid-refresh leaves the graph half-updated, which is far worse than a
|
|
# spare GB. This follows the page cache: Neo4j's own rule of thumb is heap + page cache + ~1G, so
|
|
# 2G of cache means 6g here — 1G of reserve, not generosity. Do not raise the page cache without
|
|
# raising this too. 6g -> 8g with the heap raise to 4G (same rule: 4G heap + 2G cache + reserve).
|
|
mem_limit: 8g
|
|
volumes:
|
|
- neo4j-data:/data
|
|
healthcheck:
|
|
test: [ "CMD-SHELL", "cypher-shell -u neo4j -p agenticcode 'RETURN 1' || exit 1" ]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 20
|
|
start_period: 30s
|
|
|
|
ac-code-server:
|
|
build:
|
|
# Repository root, not ./ac-code-server: the image also carries the TypeScript sidecar from
|
|
# ac-parser-typescript/sidecar (item 192). The root .dockerignore limits what is sent.
|
|
context: .
|
|
dockerfile: ac-code-server/src/main/docker/Dockerfile.jvm
|
|
container_name: agenticcode-server
|
|
ports:
|
|
- "8787:8787"
|
|
environment:
|
|
NEO4J_URI: bolt://neo4j:7687
|
|
NEO4J_USER: neo4j
|
|
NEO4J_PASSWORD: agenticcode
|
|
# JDK_JAVA_OPTIONS (not JAVA_OPTS) — the entrypoint is `java -jar`, which expands no shell
|
|
# variable; the JVM reads this one by itself. Both settings must live here: a value set in
|
|
# compose replaces the image's, it does not append, so the log-manager property would be
|
|
# silently dropped if it were left in the Dockerfile.
|
|
#
|
|
# -Xmx2500m. Ergonomics would allow 7956 MB, and the process then kept 4.91 GiB resident an
|
|
# hour after a refresh had ended. Sizing history, because the first cap was too tight: a deep
|
|
# *refresh* peaked at 1593 MB, which suggested 2 GB — but a `project recreate --deep` (heavier:
|
|
# ingests from empty) then peaked at 1924 MB, i.e. 94% of that cap. 2500m restores ~25% headroom
|
|
# while keeping nearly all of the reduction.
|
|
# G1PeriodicGCInterval returns committed-but-unused heap to the OS while idle.
|
|
JDK_JAVA_OPTIONS: >-
|
|
-Xmx2500m
|
|
-XX:G1PeriodicGCInterval=300000
|
|
-Djava.util.logging.manager=org.jboss.logmanager.LogManager
|
|
# Heap 2.5G + metaspace/code cache/direct buffers. Measured RSS peak was 3472 MB against a 3 GB
|
|
# heap cap, i.e. ~1.9 GB non-heap. Item 192 adds the TypeScript sidecar, a Node process the JVM
|
|
# runs per npm workspace during a deep pass: measured ~0.75 GB RSS per workspace, capped at
|
|
# --max-old-space-size=1024 and run before the JVM's own persist/enrichment peak — so 4g would
|
|
# have been tight only if the two peaks coincided; 5g leaves room for that case.
|
|
mem_limit: 5g
|
|
volumes:
|
|
# Mounted at the same absolute host path so project roots registered via
|
|
# the API (which store absolute host paths) resolve inside the container too.
|
|
# One entry per registered project root (GET /api/projects) — add a line
|
|
# here whenever a new project root is registered outside this repo.
|
|
- /home/ingo/deve/agenticCode:/home/ingo/deve/agenticCode:ro
|
|
- /home/ingo/deve/uniqa/uniqa-upms-app:/home/ingo/deve/uniqa/uniqa-upms-app:ro
|
|
- /home/ingo/deve/uniqa/pur-sources/backend:/home/ingo/deve/uniqa/pur-sources/backend:ro
|
|
# Item 192: the pur frontend (project `purfe`, language typescript). Read-only like the others;
|
|
# the sidecar runs with noEmit and reads the frontend's own node_modules for library typings.
|
|
- /home/ingo/deve/uniqa/pur-sources/frontend:/home/ingo/deve/uniqa/pur-sources/frontend:ro
|
|
- /home/ingo/deve/tools/conqat/system/src/250401_UMPS/src/pur-analysis/pur-legacy:/home/ingo/deve/tools/conqat/system/src/250401_UMPS/src/pur-analysis/pur-legacy:ro
|
|
depends_on:
|
|
neo4j:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
|
|
ac-ui:
|
|
build:
|
|
context: ./ac-ui
|
|
dockerfile: Dockerfile
|
|
container_name: agenticcode-ui
|
|
ports:
|
|
- "5174:80"
|
|
depends_on:
|
|
- ac-code-server
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
neo4j-data:
|