Skip to content

Commit 1f23846

Browse files
committed
TIKA-4809: Update docs for /meta's pipes migration and the error-response policy
1 parent 0fdd6cf commit 1f23846

3 files changed

Lines changed: 126 additions & 63 deletions

File tree

docs/modules/ROOT/pages/migration-to-4x/migrating-tika-server-4x.adoc

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
2222
== Overview
2323
24-
Tika Server 4.x introduces pipes-based parsing for the main content-extraction endpoints (`/tika`, `/rmeta`, `/unpack`), which provides process isolation for those operations. This improves stability and resource management but introduces some breaking changes. A few endpoints (notably `/meta`) still parse in-process in the request-handling JVM.
24+
Tika Server 4.x introduces pipes-based parsing for the main content-extraction endpoints (`/tika`, `/rmeta`, `/unpack`, `/meta`), which provides process isolation for those operations. This improves stability and resource management but introduces some breaking changes.
2525
2626
== New `/tika` Endpoint Structure
2727
@@ -112,6 +112,29 @@ The HTTP status codes are also more precise:
112112
that branch only on HTTP status code are unaffected unless they were treating
113113
`UNSPECIFIED_CRASH` as a `500`.
114114
115+
=== `/meta` Is Now Pipes-Backed
116+
117+
`/meta` previously parsed in-process, in the request-handling JVM, with no crash
118+
isolation and its own ad hoc error handling (`500` for most parse failures, `400`
119+
for a field that couldn't be extracted from an incompletely-parsed document). It
120+
now shares the same pipes-backed `PipesParser` as `/tika`, `/rmeta`, and `/unpack`
121+
(see
122+
xref:using-tika/server/index.adoc#_endpoints_and_forked_process_groups[Endpoints
123+
and Forked-Process Groups]), with the same crash isolation and the same
124+
per-document exception handling as those endpoints (see
125+
xref:using-tika/server/index.adoc#_error_responses[Error Responses]):
126+
127+
* `/meta`, `/meta/form`, `/meta/config` now return `200 OK` with the exception
128+
embedded in `tk:exception:container-exception`, instead of `500`.
129+
* `/meta/\{field}` now returns `422 Unprocessable Entity` for a genuine parse
130+
exception, instead of `500` or `400`.
131+
132+
**Migration:** clients that treated any non-`200` from `/meta` as "parse failed"
133+
should check the new status codes above. Clients that inspected the response body
134+
for error text should check `tk:exception:container-exception` (full-object
135+
endpoints) or the `422` body (`/meta/\{field}`, populated only when
136+
`returnStackTrace=true`).
137+
115138
=== Accept Header Routing Removed
116139
117140
The `/tika` endpoint no longer routes based on `Accept` headers. Use explicit paths instead:

docs/modules/ROOT/pages/pipes/cpu-sizing.adoc

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -119,20 +119,20 @@ Everything above describes sizing for *one* `PipesParser` — one `pipes`
119119
config section, one set of forked workers. The auto-sizer has no visibility
120120
into anything else running in the same JVM.
121121

122-
This matters concretely for tika-server: `/tika`+`/rmeta`+`/unpack`, `/pipes`,
123-
and `/async` are backed by *three independent* groups when all are enabled in
124-
the same server — `/tika`+`/rmeta`+`/unpack` and `/pipes` are each their own
125-
`PipesParser` instance, and `/async` manages its own forked-worker pool
126-
directly (not via `PipesParser` at all, though it uses the same underlying
127-
auto-sizer). Each group's auto-sizer computes its slice from
128-
`Runtime.availableProcessors()` as if it were the only consumer on the host —
129-
it does not know sibling groups in the same process are about to fork their
130-
own `numClients` workers too. The result: with `numClients=2` on all three,
131-
you get 6 total forked JVMs, each capped assuming exclusive access to the
132-
whole host. Whether that's *actually* oversubscribed depends on your host's
133-
real core count relative to those combined `numClients` values — it's not
134-
automatic, but the auto-sizer also won't warn you, because each group looks
135-
correctly sized from its own perspective alone. See
122+
This matters concretely for tika-server: `/tika`+`/rmeta`+`/unpack`+`/meta`+
123+
`/pipes` and `/async` are backed by *two independent* groups when both are
124+
enabled in the same server — the first five endpoints share one `PipesParser`
125+
instance, and `/async` manages its own forked-worker pool directly (not via
126+
`PipesParser` at all, though it uses the same underlying auto-sizer). Each
127+
group's auto-sizer computes its slice from `Runtime.availableProcessors()` as
128+
if it were the only consumer on the host — it does not know the sibling group
129+
in the same process is about to fork its own `numClients` workers too. The
130+
result: with `numClients=2` on both, you get 4 total forked JVMs, each capped
131+
assuming exclusive access to the whole host. Whether that's *actually*
132+
oversubscribed depends on your host's real core count relative to those
133+
combined `numClients` values — it's not automatic, but the auto-sizer also
134+
won't warn you, because each group looks correctly sized from its own
135+
perspective alone. See
136136
xref:using-tika/server/index.adoc#_endpoints_and_forked_process_groups[Endpoints
137137
and Forked-Process Groups] for the tika-server-specific guidance.
138138

docs/modules/ROOT/pages/using-tika/server/index.adoc

Lines changed: 88 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,23 @@ This section covers running Apache Tika as a REST server via `tika-server`.
2424
Tika Server provides a RESTful HTTP interface for parsing documents and extracting
2525
content. It can be deployed as a standalone service or in a containerized environment.
2626

27-
In Tika 4.x, the main content-extraction endpoints — `/tika`, `/rmeta`, and
28-
`/unpack` — parse in forked child processes via the Tika Pipes infrastructure.
29-
This provides process isolation (a parser crash or OOM in a child cannot take
30-
down the request-handling process) at the cost of requiring a Pipes
31-
configuration. A few endpoints (notably `/meta`) still parse in-process in the
32-
request-handling JVM; treat those as best-effort under load. See
27+
In Tika 4.x, the main content-extraction endpoints — `/tika`, `/rmeta`,
28+
`/unpack`, and `/meta` — parse in forked child processes via the Tika Pipes
29+
infrastructure. This provides process isolation (a parser crash or OOM in a
30+
child cannot take down the request-handling process) at the cost of requiring
31+
a Pipes configuration. See
3332
xref:migration-to-4x/migrating-tika-server-4x.adoc[Migrating Tika Server to 4.x]
3433
for the full breaking-change list when upgrading from 3.x.
3534

3635
[IMPORTANT]
3736
====
3837
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
38+
`allowPipes=true` and refuse to start without it). `/tika`, `/rmeta`,
39+
`/unpack`, and `/meta` are **on by default** — the moment you run a basic
40+
`tika-server` and PUT a document to `/tika`, you are running Tika Pipes, with
41+
a real forked child process behind it. If you're upgrading from 3.x, where
42+
these endpoints parsed in-process in a single JVM, this is a profound change:
43+
`pipes.numClients` now controls both
4644
how many requests these endpoints can serve concurrently and how many forked
4745
JVMs run at once, and it's easy to size it thinking about only one of those
4846
two things. Undersized for your request volume, and callers start waiting —
@@ -200,6 +198,12 @@ is a plain opt-in endpoint — enable it simply by listing it under `endpoints`.
200198

201199
== Error Responses
202200

201+
tika-server distinguishes two different kinds of failure: the forked worker itself
202+
dying, and the worker running fine but catching an exception while parsing one
203+
particular document. They get different treatment.
204+
205+
=== Process-level failures
206+
203207
When parsing fails due to a process-level problem — the forked child process timed out,
204208
ran out of memory, or crashed unexpectedly — the server returns an HTTP error with a
205209
JSON body whose shape matches the `PipesResult` status:
@@ -239,10 +243,54 @@ crashing" — you can tell them apart from the status code alone.
239243
document on the same server is unlikely to succeed without a configuration fix.
240244
|===
241245

242-
NOTE: A successful parse that encountered internal parser errors (e.g. a truncated
243-
embedded document) still returns `200 OK`. The partial-parse exception is surfaced
244-
in the `tk:exception:container-exception` metadata field of the response, not as an
245-
HTTP error code.
246+
=== Per-document parse exceptions
247+
248+
A process-level failure (above) means the worker itself is gone — nothing was parsed.
249+
A per-document parse exception is different: the worker ran to completion and simply
250+
caught an exception while parsing this one document (an encrypted file with no
251+
password, a malformed embedded object, an NPE in a specific parser). The worker is
252+
healthy, and whatever content it managed to extract is still available.
253+
254+
Which HTTP status this gets depends on whether the response shape has room to embed
255+
the exception alongside content:
256+
257+
[cols="1,1,3"]
258+
|===
259+
|Endpoints |Status |Behavior
260+
261+
|`/rmeta`, `/tika/json`, `/meta`'s full-object endpoints
262+
|`200 OK`
263+
|The exception is embedded in the response's `tk:exception:container-exception`
264+
field (or `tk:exception:embedded-exception` on an individual embedded document
265+
within an `/rmeta` list), alongside whatever content and metadata were captured.
266+
Partial success is meaningful here — a batch/list response, or a structured object
267+
with room for an extra field.
268+
269+
|`/tika`'s raw endpoints (`text`, `html`, `xml`, `md`)
270+
|`422 Unprocessable Entity`
271+
|A raw byte-stream response has no field to embed the exception in, so the status
272+
itself signals the failure — but the body still carries whatever content was
273+
actually extracted, not an empty or generic error body.
274+
275+
|`/meta/\{field}`
276+
|`422 Unprocessable Entity`
277+
|A single scalar value has nowhere to embed the exception either, so it's thrown
278+
rather than silently returned as if the field were simply absent.
279+
280+
|`/unpack`
281+
|`422 Unprocessable Entity`
282+
|Same reasoning as the raw endpoints, but content is *not* currently preserved —
283+
any files already unpacked before the exception are discarded. This is a known
284+
gap, not yet addressed.
285+
|===
286+
287+
By default (`returnStackTrace=false`), any exception text exposed this way is trimmed
288+
to just the exception's class and message — not the full stack trace, which can
289+
reveal internal file paths and library internals. For the `200 OK` family the
290+
trimmed field is still always present when a failure occurred, so callers can detect
291+
it either way; for the `422` family, the body carries no exception text at all unless
292+
`returnStackTrace=true`. Set `returnStackTrace=true` to get the full trace — useful
293+
in development, best left off in production.
246294

247295
== Configuration
248296

@@ -260,7 +308,7 @@ Server behavior beyond host/port is controlled by a JSON config file passed via
260308

261309
|`endpoints`
262310
|_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`.
311+
|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`/`/unpack`/`/meta`/`/pipes` with `/async`.
264312

265313
|`allowPerRequestConfig`
266314
|`false`
@@ -298,27 +346,19 @@ xref:migration-to-4x/migrating-tika-server-4x.adoc#_configuration_changes[Config
298346
[#_endpoints_and_forked_process_groups]
299347
== Endpoints and Forked-Process Groups
300348

301-
Three 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`** is its own separate group (gated behind `allowPipes`) — it
307-
builds its own independent `PipesParser`, not shared with `/tika`/`/rmeta`/
308-
`/unpack`, sized by the same `pipes.numClients` setting in the same config
309-
but as a wholly separate set of forked processes.
310-
* **`/async`** is a *third*, independent group (also gated behind
311-
`allowPipes`) — it doesn't share a `PipesParser` with `/pipes` either. It
312-
manages its own forked-worker pool directly (queued/background processing,
313-
results delivered via a configured `PipesReporter` rather than in the HTTP
314-
response), sized by its own read of `pipes.numClients` from the same config.
315-
* **`/meta` is not pipes-backed** — it still parses in-process, in the
316-
request-handling JVM, as in 3.x. It isn't bound by `numClients` and doesn't
317-
participate in anything below, but it also has no crash/OOM isolation: a
318-
hostile or pathological document sent to `/meta` can affect the
319-
request-handling process itself, unlike the pipes-backed endpoints where the
320-
same document only takes down a forked child. Treat `/meta` as best-effort
321-
under adversarial input.
349+
Two independent forked-process groups exist:
350+
351+
* **`/tika` + `/rmeta` + `/unpack` + `/meta` + `/pipes`** share one group —
352+
all five go through the same `PipesParsingHelper`/`PipesParser`, sized by
353+
`pipes.numClients`. `/pipes` still requires `allowPipes` to actually start
354+
(the server refuses to start if it's listed without that flag) even though it
355+
shares its parser with the always-on endpoints; the others don't require
356+
`allowPipes`.
357+
* **`/async`** is a separate group (gated behind `allowPipes`) — it doesn't
358+
share a `PipesParser` with the group above at all. It manages its own
359+
forked-worker pool directly (queued/background processing, results delivered
360+
via a configured `PipesReporter` rather than in the HTTP response), sized by
361+
its own read of `pipes.numClients` from the same config.
322362

323363
Within a pipes-backed group, `numClients` does two *separate* jobs, and it's
324364
worth understanding both before picking a value.
@@ -346,15 +386,15 @@ Independently of the above, each group also auto-sizes its forked JVMs'
346386
`-XX:ActiveProcessorCount` from `numClients` and the host's core count — see
347387
xref:pipes/cpu-sizing.adoc[Forked-JVM CPU Sizing] for the full mechanics. This
348388
part *can* go wrong across groups: the auto-sizer for one group has no
349-
visibility into another group running in the same process, so if you enable
350-
`/tika`/`/rmeta`/`/unpack` together with `/pipes` and/or `/async` — a config
351-
listing all of them, or simply leaving `endpoints` unset while
352-
`allowPipes=true` gives you all three groups at once — each group's auto-sizer
353-
computes its slice as if it owned the whole host. Whether that actually causes
354-
oversubscription depends on your `numClients` values relative to the host's
355-
core count; it's not automatic, but it's also not something the auto-sizer
356-
will warn you about, because from any one group's perspective alone the sizing
357-
looks fine. See
389+
visibility into the other group running in the same process, so if you enable
390+
`/async` alongside the shared group — a config listing `async` together with
391+
any of `tika`/`rmeta`/`unpack`/`meta`/`pipes`, or simply leaving `endpoints`
392+
unset while `allowPipes=true` gives you both groups at once — each group's
393+
auto-sizer computes its slice as if it owned the whole host. Whether that
394+
actually causes oversubscription depends on your `numClients` values relative
395+
to the host's core count; it's not automatic, but it's also not something the
396+
auto-sizer will warn you about, because from either group's perspective alone
397+
the sizing looks fine. See
358398
xref:pipes/cpu-sizing.adoc#_known_limitation_multiple_pipes_groups_in_one_process[Known
359399
limitation: multiple Pipes groups in one process] for the mechanics and
360400
mitigation (scope `endpoints` to what you actually use, or set

0 commit comments

Comments
 (0)