Skip to content

TIKA-4839 - simplify signature - #3081

Merged
tballison merged 7 commits into
mainfrom
TIKA-4839-tweaks
Aug 27, 2026
Merged

TIKA-4839 - simplify signature#3081
tballison merged 7 commits into
mainfrom
TIKA-4839-tweaks

Conversation

@tballison

Copy link
Copy Markdown
Contributor

Thanks for your contribution to Apache Tika! Your help is appreciated!

Before opening the pull request, please verify that

  • there is an open issue on the Tika issue tracker which describes the problem or the improvement. We cannot accept pull requests without an issue because the change wouldn't be listed in the release notes.
  • the issue ID (TIKA-XXXX)
    • is referenced in the title of the pull request
    • and placed in front of your commit messages surrounded by square brackets ([TIKA-XXXX] Issue or pull request title)
  • commits are squashed into a single one (or few commits for larger changes)
  • Tika is successfully built and unit tests pass by running ./mvnw clean test
  • there should be no conflicts when merging the pull request branch into the recent main branch. If there are conflicts, please try to rebase the pull request branch on top of a freshly pulled main branch
  • if you add new module that downstream users will depend upon add it to relevant group in tika-bom/pom.xml.

We will be able to faster integrate your pull request if these conditions are met. If you have any questions how to fix your problem or about using Tika in general, please sign up for the Tika mailing list. Thanks!

@THausherr
THausherr requested a lite review from Copilot August 27, 2026 11:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Simplifies the ServerManager restart-reporting API to a single generation-aware spelling and tightens client/manager behavior around worker restarts and shutdown races.

Changes:

  • Remove legacy ServerManager restart-reporting overloads in favor of markServerForRestart(RestartReason, long) and handleCrashAndGetExitCode(long) as abstract methods.
  • Update server-manager implementations and test fakes to track generation and restart marking consistently.
  • Make PipesClient gracefully return FAILED_TO_INITIALIZE when initialization races with manager shutdown.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tika-pipes/tika-pipes-integration-tests/src/test/java/org/apache/tika/pipes/core/PipesClientTest.java Adds an assertion that the client backstop triggers a worker restart mark.
tika-pipes/tika-pipes-core/src/test/java/org/apache/tika/pipes/core/ServerManagerMarkContractTest.java Removes now-obsolete tests for deprecated overload spellings.
tika-pipes/tika-pipes-core/src/test/java/org/apache/tika/pipes/core/SentinelServerManager.java Updates test sentinel to implement new abstract ServerManager methods and capture restart reason.
tika-pipes/tika-pipes-core/src/test/java/org/apache/tika/pipes/core/PipesClientPayloadLimitTest.java Asserts oversized payload rejection does not recycle a healthy worker.
tika-pipes/tika-pipes-core/src/test/java/org/apache/tika/pipes/core/PipesClientInterruptTest.java Asserts interrupt recycling happens via abandonment, not explicit marking (avoids double counting).
tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/SharedServerManager.java Removes old overloads; relies on the new generation-aware methods.
tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/ServerManager.java Collapses restart-reporting surface to one spelling; makes methods abstract.
tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/PipesClient.java Converts an init-time IllegalStateException into a FAILED_TO_INITIALIZE result.
tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/PerClientServerManager.java Adds per-client generation tracking; synchronizes restart marking; implements new API.
CHANGES.txt Documents the behavior and API surface changes under TIKA-4839.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@THausherr
THausherr requested a lite review from Copilot August 27, 2026 15:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

}

@Override
public void close() {
Comment on lines +238 to +247
} catch (IllegalStateException e) {
// The manager was closed underneath us: a request thread racing PipesParser.close()
// or AsyncProcessor.close(), which interrupts workers without awaiting them. Nothing
// to restart and nothing to recover -- but report it rather than letting an unchecked
// exception escape PipesParser.parse() to a caller that cannot act on it.
LOG.warn("clientId={}: server manager closed while initializing {}", pipesClientId,
t.getId(), e);
closeConnection();
return buildFatalResult(t.getId(), t.getEmitKey(), PipesResult.RESULT_STATUS.FAILED_TO_INITIALIZE,
intermediateResult.get(), e.getMessage());
Comment on lines +104 to 120
long getGeneration();

/**
* The reasonless spelling of the above, kept for callers that cannot attribute the failure.
* Routed through the reason form rather than the bare no-arg default: that default exists
* only to keep pre-RestartReason implementations working, and delegating here would leave
* this silently inert for any implementation that overrides only the reason form.
*/
default void markServerForRestart(long generation) {
markServerForRestart(RestartReason.CRASH, generation);
}

/**
* As {@link #handleCrashAndGetExitCode()}, but only if {@code generation} is still current.
* Marks the server for restart due to a fatal error, attributed to {@code reason}, but only
* if {@code generation} is still current -- reports about a superseded process are dropped.
* <p>
* Called by a client that received a fatal status: the process is stopping even if
* {@link #isRunning()} still says otherwise, and the next {@link #ensureRunning()} waits for
* it to exit and restarts it.
* <p>
* Deliberately the only spelling, and deliberately abstract. Earlier revisions offered a
* no-arg and a reasonless form defaulting to one another; an implementation that overrode
* only one left the others silently inert, which is how a worker known to be poisoned kept
* being handed documents.
*/
default int handleCrashAndGetExitCode(long generation) {
return handleCrashAndGetExitCode();
}
void markServerForRestart(RestartReason reason, long generation);

Comment thread CHANGES.txt Outdated
Comment on lines 3 to 12
* tika-pipes: a parse that raced PipesParser.close()/AsyncProcessor.close()
threw IllegalStateException out of PipesParser.parse() in per-client mode;
both modes now return a FAILED_TO_INITIALIZE result, which a caller can act
on. ServerManager's restart-reporting surface is reduced to one spelling --
markServerForRestart(RestartReason, long) and handleCrashAndGetExitCode(long),
both abstract. The previous no-arg and reasonless forms defaulted to one
another, so an implementation that overrode only one left the others
silently inert (TIKA-4839).

* Add Micrometer reporting and opt-in endpoint for tika-server (TIKA-4839).
@THausherr
THausherr requested a lite review from Copilot August 27, 2026 17:52
@tballison

Copy link
Copy Markdown
Contributor Author

Last commit was vanity to say something to copilot. I think we're good.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Comment on lines +104 to +119
long getGeneration();

/**
* The reasonless spelling of the above, kept for callers that cannot attribute the failure.
* Routed through the reason form rather than the bare no-arg default: that default exists
* only to keep pre-RestartReason implementations working, and delegating here would leave
* this silently inert for any implementation that overrides only the reason form.
*/
default void markServerForRestart(long generation) {
markServerForRestart(RestartReason.CRASH, generation);
}

/**
* As {@link #handleCrashAndGetExitCode()}, but only if {@code generation} is still current.
* Marks the server for restart due to a fatal error, attributed to {@code reason}, but only
* if {@code generation} is still current -- reports about a superseded process are dropped.
* <p>
* Called by a client that received a fatal status: the process is stopping even if
* {@link #isRunning()} still says otherwise, and the next {@link #ensureRunning()} waits for
* it to exit and restarts it.
* <p>
* Deliberately the only spelling, and deliberately abstract. Earlier revisions offered a
* no-arg and a reasonless form defaulting to one another; an implementation that overrode
* only one left the others silently inert, which is how a worker known to be poisoned kept
* being handed documents.
*/
default int handleCrashAndGetExitCode(long generation) {
return handleCrashAndGetExitCode();
}
void markServerForRestart(RestartReason reason, long generation);
markServerForRestart(RestartReason.CRASH);
return -1;
}
int handleCrashAndGetExitCode(long generation);
Comment thread CHANGES.txt Outdated
Comment on lines +1 to +5
Release 4.1.0 - unreleased

* PDF: extractFontNames threw NullPointerException on a page with no
/Resources dictionary (TIKA-4842).

* tika-server: opt-in Micrometer metrics reporting and endpoint
(TIKA-4839).

* Per-request (parse-context) config for parsers that lock fields
(Tess4J, VLM, OpenAI image-embedding) threw even when empty; locked
fields are still rejected when actually set (TIKA-4843).

* OOXML: new msoffice:has-unreferenced-parts and
msoffice:unreferenced-part-names flag package parts unreachable via the
OPC relationship graph. Structural only, expect false positives; not
applied to XPS (TIKA-4837).

* Shared pipes server (useSharedServer: true): a worker death could trigger
a second, spurious restart that killed the healthy replacement. Forks now
carry a generation; stale reports are dropped. Also fixed: a fork after
shutdown() that was never destroyed, and a temp-dir leak on interrupt
during teardown (TIKA-4844).

* tika-pipes cache memory budget defaults to a quarter of the fork heap;
override with -Dtika.pipes.cacheMemoryBudgetBytes in forkedJvmArgs
(<=0 disables). TikaInputStream: hasFile() also reports cache spills,
toString() no longer spills, new inMemoryContent(channel). Digester gains
digestSink(); a digest is published only on commit(), so failed or empty
translations (e.g. stub PST items) publish no digest. New
TemporaryResources.closeAll(Closeable...) (TIKA-4835).

* Docs/javadocs reconciled with the code: ES/OpenSearch attachmentStrategy
has no default; Kafka connectionsMaxIdleMs is honored; jdbc
queryTimeoutSeconds 0 is not "no limit"; Solr basic auth only; pipes
reporters/iterators are built at config load; Tess4J also locks poolSize
and maxImagePixels; pdf:trapped is new, not renamed; plugin config
nesting fixed in 23 javadocs (TIKA-4842).

* Pipes plugins no longer bundle Jackson; the host provides it. Plugin
config is parsed by a shared strict PluginJson mapper (rejects unknown
and duplicate keys; accepts comments) (TIKA-4840).

* tika-server and tika-async-cli accept // and /* */ comments in config
during override merging, as documented (TIKA-4834).

* Kafka pipes iterator no longer stops on the first empty poll; waits for
partition assignment (assignmentTimeoutMs, 30s) and a quiet window
(drainIdleMs, 1s). groupInitialRebalanceDelayMs is deprecated
(TIKA-4833).

* Pipes IPC carries inline bytes as a raw binary field, not in the tuple;
Smile 7-bit binary encoding disabled. 4.0.0 tuples with an "inline-bytes"
parse-context entry are rejected (TIKA-4829).

* Digesting embedded documents no longer spools each to a temp file; a
process-wide CacheMemoryBudget (default 256MB) keeps them in memory. New
TikaInputStream API: get(IOSupplier,...), enableRewind(CacheMemoryBudget),
getSeekableByteChannel(). Zip-family parsing and detection use seekable
channels, so hasFile() may be false afterward; getPath() still spools on
demand (TIKA-4828).

* Pipes carries the client Content-Type into the forked worker as a
detection hint for all forked endpoints; honored only when it equals or
specializes the detected type, or when there is no magic. The
user-override key is not carried (TIKA-4825).

* OneNote: document-order extraction, superseded revisions omitted, embedded
BLOBs extracted, warnings and relationship IDs in metadata, bounded
recursion/allocation; malformed files fall back to the legacy string dump
* tika-pipes: a parse racing PipesParser.close() now returns FAILED_TO_INITIALIZE
instead of throwing IllegalStateException. ServerManager restart reporting is
now the single abstract pair markServerForRestart(RestartReason, long) and
public void closedManagerDuringInitReturnsFailedToInitialize() throws Exception {
try (ServerSocket serverSocket = new ServerSocket(0)) {
SentinelServerManager manager = new SentinelServerManager(serverSocket.getLocalPort());
manager.closed = true;
Comment on lines +238 to 248
} catch (IllegalStateException e) {
// Typically the manager was closed underneath us: a request thread racing PipesParser.close()
// or AsyncProcessor.close(), which interrupts workers without awaiting them. Nothing
// to restart and nothing to recover -- but report it rather than letting an unchecked
// exception escape PipesParser.parse() to a caller that cannot act on it.
LOG.warn("clientId={}: server manager rejected initialization of {}", pipesClientId,
t.getId(), e);
closeConnection();
return buildFatalResult(t.getId(), t.getEmitKey(), PipesResult.RESULT_STATUS.FAILED_TO_INITIALIZE,
intermediateResult.get(), e.getMessage());
}
@tballison
tballison merged commit ff2d687 into main Aug 27, 2026
4 checks passed
@tballison
tballison deleted the TIKA-4839-tweaks branch August 27, 2026 18:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants