@@ -33,6 +33,29 @@ request-handling JVM; treat those as best-effort under load. See
3333xref:migration-to-4x/migrating-tika-server-4x.adoc[Migrating Tika Server to 4.x]
3434for the full breaking-change list when upgrading from 3.x.
3535
36+ [IMPORTANT]
37+ ====
38+ This is not opt-in the way `/pipes` and `/async` are (those require
39+ `allowPipes=true` and refuse to start without it). `/tika`, `/rmeta`, and
40+ `/unpack` are **on by default** — the moment you run a basic `tika-server` and
41+ PUT a document to `/tika`, you are running Tika Pipes, with a real forked
42+ child process behind it. (`/meta` is the exception among the main
43+ content-extraction endpoints — it still parses in-process; see below.) If
44+ you're upgrading from 3.x, where these endpoints parsed in-process in a
45+ single JVM, this is a profound change: `pipes.numClients` now controls both
46+ how many requests these endpoints can serve concurrently and how many forked
47+ JVMs run at once, and it's easy to size it thinking about only one of those
48+ two things. Undersized for your request volume, and callers start waiting —
49+ then failing with `429`s — under load that used to just queue up on request
50+ threads in 3.x. Oversized for your host's core count, and the forked workers
51+ individually starve each other of CPU. Neither shows up as an error in your
52+ own code; both show up as "the server got slower" with nothing pointing at
53+ `numClients` as the cause. See
54+ <<_endpoints_and_forked_process_groups,Endpoints and Forked-Process Groups>>
55+ below and xref:pipes/cpu-sizing.adoc[Forked-JVM CPU Sizing] before deploying —
56+ don't treat the `numClients` value in example configs as safe boilerplate.
57+ ====
58+
3659== Security
3760
3861IMPORTANT: The primary rule is *trusted callers only*. `tika-server` is not a security boundary:
@@ -196,10 +219,17 @@ a `message` field is also included (it often contains a server-side stack trace)
196219|HTTP status |`status` values |Meaning
197220
198221|`503 Service Unavailable`
199- |`TIMEOUT`, `OOM`, `UNSPECIFIED_CRASH`, `CLIENT_UNAVAILABLE_WITHIN_MS`
200- |The forked parse process failed, or no parse client became available within the
201- configured wait time (`CLIENT_UNAVAILABLE_WITHIN_MS`). The server is still healthy;
202- the client may retry.
222+ |`TIMEOUT`, `OOM`, `UNSPECIFIED_CRASH`
223+ |The forked parse process actually failed (crashed, OOM'd, or exceeded its timeout).
224+ The server is still healthy; the client may retry.
225+
226+ |`429 Too Many Requests`
227+ |`CLIENT_UNAVAILABLE_WITHIN_MS`
228+ |Nothing failed — no parse client became available within the configured wait time
229+ (deliberate backpressure, not a bug; see <<_endpoints_and_forked_process_groups,Endpoints
230+ and Forked-Process Groups>>). Distinct from `503` above on purpose: a `429` spike means
231+ "raise `numClients` or add capacity," a `503` spike means "something is actually
232+ crashing" — you can tell them apart from the status code alone.
203233
204234|`500 Internal Server Error`
205235|`FAILED_TO_INITIALIZE`, `FETCH_EXCEPTION`, `EMIT_EXCEPTION`,
@@ -228,6 +258,10 @@ Server behavior beyond host/port is controlled by a JSON config file passed via
228258|`false`
229259|Opt-in for the `/pipes` and `/async` endpoints, which drive process-isolated fetching and parsing. The server refuses to start if either is selected without this flag (see <<_security_configuration,Security Configuration>>).
230260
261+ |`endpoints`
262+ |_all defaults_
263+ |Which endpoints to expose. Leave unset to get the full default set (includes `/tika` and `/rmeta`). Explicitly listing endpoints also controls how many independent forked-process groups you run — see <<_endpoints_and_forked_process_groups,Endpoints and Forked-Process Groups>> below before combining `/tika`/`/rmeta` with `/pipes`/`/async`.
264+
231265|`allowPerRequestConfig`
232266|`false`
233267|Opt-in for per-request parser configuration: the `/config` family of endpoints and the multipart `config` part. When off, such requests are rejected with 403 (see <<_security_configuration,Security Configuration>>).
@@ -261,6 +295,64 @@ For the full Pipes-related sections (`pipes`, `fetchers`, `emitters`, `parse-con
261295that tika-server 4.x requires, see
262296xref:migration-to-4x/migrating-tika-server-4x.adoc#_configuration_changes[Configuration Changes].
263297
298+ [#_endpoints_and_forked_process_groups]
299+ == Endpoints and Forked-Process Groups
300+
301+ Two independent pipes-backed process groups exist, plus one endpoint that
302+ isn't pipes-backed at all:
303+
304+ * **`/tika` + `/rmeta` + `/unpack`** share one group — all three go through
305+ the same `PipesParsingHelper`/`PipesParser`, sized by `pipes.numClients`.
306+ * **`/pipes` + `/async`** share a separate group (gated behind `allowPipes`),
307+ sized by the same `pipes.numClients` setting in the same config, but as an
308+ independent set of forked processes.
309+ * **`/meta` is not pipes-backed** — it still parses in-process, in the
310+ request-handling JVM, as in 3.x. It isn't bound by `numClients` and doesn't
311+ participate in anything below, but it also has no crash/OOM isolation: a
312+ hostile or pathological document sent to `/meta` can affect the
313+ request-handling process itself, unlike the pipes-backed endpoints where the
314+ same document only takes down a forked child. Treat `/meta` as best-effort
315+ under adversarial input.
316+
317+ Within a pipes-backed group, `numClients` does two *separate* jobs, and it's
318+ worth understanding both before picking a value.
319+
320+ === It bounds how many requests that group can serve at once
321+
322+ Each group holds a fixed pool of `numClients` workers. A request that arrives
323+ when all of them are busy doesn't fail immediately — it waits, up to
324+ `pipes.maxWaitForClientMillis` (default 60s), for one to free up. This is
325+ deliberate backpressure, not a bug: if a worker frees up in time, the request
326+ is served normally; if the wait times out, the server returns `429` with
327+ `status: CLIENT_UNAVAILABLE_WITHIN_MS` — an explicit "I'm at capacity, retry"
328+ signal, not a crash (see <<_error_responses,Error Responses>> above). Under
329+ 3.x's in-process model there was no equivalent hard cap — requests just piled
330+ up on the HTTP server's own thread pool instead. If you're seeing
331+ `CLIENT_UNAVAILABLE_WITHIN_MS` under real load, that's this group's
332+ concurrency limit telling you it's undersized for your request volume: raise
333+ `numClients` for more concurrent capacity, or tune `maxWaitForClientMillis` to
334+ fail faster (surface backpressure to the caller sooner) or more patiently
335+ (absorb bursts, at the cost of tying up more request threads while waiting).
336+
337+ === It sizes each forked worker's view of available CPU
338+
339+ Independently of the above, each group also auto-sizes its forked JVMs'
340+ `-XX:ActiveProcessorCount` from `numClients` and the host's core count — see
341+ xref:pipes/cpu-sizing.adoc[Forked-JVM CPU Sizing] for the full mechanics. This
342+ part *can* go wrong across groups: the auto-sizer for one group has no
343+ visibility into another group running in the same process, so if you enable
344+ both `/tika`/`/rmeta`/`/unpack` *and* `/pipes`/`/async` together — a config
345+ listing all of them, or simply leaving `endpoints` unset while
346+ `allowPipes=true` — each group's auto-sizer computes its slice as if it owned
347+ the whole host. Whether that actually causes oversubscription depends on your
348+ `numClients` values relative to the host's core count; it's not automatic, but
349+ it's also not something the auto-sizer will warn you about, because from
350+ either group's perspective alone the sizing looks fine. See
351+ xref:pipes/cpu-sizing.adoc#_known_limitation_multiple_pipes_groups_in_one_process[Known
352+ limitation: multiple Pipes groups in one process] for the mechanics and
353+ mitigation (scope `endpoints` to what you actually use, or set
354+ `-XX:ActiveProcessorCount` explicitly with the combined total in mind).
355+
264356== Topics
265357
266358* xref:using-tika/server/tls.adoc[TLS/SSL Configuration] — Secure your server with TLS and mutual authentication
0 commit comments