Repository navigation
Description
Problem
The CD plugin fetches every included type over HTTP, including the types the app serves itself, by calling itself on loopback. Each same-app include:
- pays a full round trip: a socket, every servlet filter, and the JSON serialised and parsed again;
- holds a second worker thread while the original request waits, so a bounded pool can starve under load;
- breaks wherever loopback can't reach the app: TLS terminated in the app, a server bound to one address, mTLS, graceful shutdown, MockMvc.
Solution
Resolve same-app types in-process, through JsonApi4j.execute(...), as the client's principal. Validation and the AC plugin still apply.
Types mapped to another service's url stay over HTTP. HTTP for same-app types becomes an explicit, per-type choice:
jsonapi4j:
cd:
mapping:
default:
url: http://127.0.0.1:8080/jsonapi # this app's own address
transport: HTTP # same-app types over HTTP by default
users:
transport: IN_PROCESS # except users
orders:
url: https://orders.internal/jsonapi # another service: always HTTPtransport: IN_PROCESS | HTTPper mapping entry. An unsettransportfalls back tomapping.default.transport, then toIN_PROCESS.- Startup validation:
HTTPwithoutmapping.default.urlis rejected;IN_PROCESSon a type with aurlis rejected;defaulttakes onlyurlandtransport.
- No more loopback-URL detection.
- In-process results bypass the include cache: they're cheap to read and always fresh.
A rough benchmark on a 3-hop include: in-process is ~1.8× faster per request, at ~1.6× the throughput.
Refactoring (resolver)
-
DomainSettingsis a sealed interface with two kinds:overHttp(...)andinProcess(...). -
Fetching is split into composable
BatchFetcher<R>decorators:OverHttp → Caching → Chunking → ErrorStrategyAware → HTTP client InProcess → Chunking → ErrorStrategyAware → InProcessBatchFetcherRoutingBatchFetcherdispatches by the route kind and stands in a null object when there is no in-process fetcher. -
HttpFetchResultis renamed toFetchResult.CachingCompoundDocsFetcher,BatchFetchResultandPrimaryResourceare removed. Resource parsing is unified inJsonApiResponseParser. -
CompoundDocsRequestcarries the principal.ResponseHeadersandResponseStatusgainclear(), andResponseHeadersalso gainstakeCacheControl().
Breaking changes
- Same-app includes no longer pass through servlet filters or URL-based security rules. To keep that, set
transport: HTTP. mapping.default.urlalone no longer switches to HTTP; it now also needsmapping.default.transport: HTTP.SelfFallbackRouting.forRequestis removed.- The resolver API renames listed above (
HttpFetchResult→FetchResult, and the removed classes).
Docs
compound-docs-plugin.md: how includes are fetched, the transport settings, and the Limitations section.performance.md: preferIN_PROCESS.compound-docs.md.- The Claude Code plugin references.
Activity
#220: CD: resolve same-app includes in-process, with per-type transpo…