This is an automated email from the ASF dual-hosted git repository.

tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/main by this push:
     new 6b4e9368dd TIKA-4919: improve logging when progress==totaltasktimeout 
(#3228)
6b4e9368dd is described below

commit 6b4e9368ddfcfac91ed95d8d7e6f259bc776bcd2
Author: Tim Allison <[email protected]>
AuthorDate: Thu Sep 24 05:59:48 2026 -0400

    TIKA-4919: improve logging when progress==totaltasktimeout (#3228)
---
 docs/modules/ROOT/pages/pipes/timeouts.adoc               |  5 ++++-
 .../main/java/org/apache/tika/config/ParseTimeout.java    |  7 +------
 .../main/java/org/apache/tika/config/TimeoutLimits.java   | 15 ++++++++++++++-
 .../java/org/apache/tika/config/TimeoutLimitsTest.java    |  8 ++++++++
 4 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/docs/modules/ROOT/pages/pipes/timeouts.adoc 
b/docs/modules/ROOT/pages/pipes/timeouts.adoc
index 4613f8397c..2b983ee67d 100644
--- a/docs/modules/ROOT/pages/pipes/timeouts.adoc
+++ b/docs/modules/ROOT/pages/pipes/timeouts.adoc
@@ -27,7 +27,10 @@ Three timeout settings bound a parse, and each answers a 
different question:
   including all of its embedded documents. Default: `3600000` (1 hour).
 
 * **`progressTimeoutMillis`** -- How long may the parse go *silent* before it 
is
-  considered hung and killed. Default: `120000` (2 minutes).
+  considered hung and killed. Default: `120000` (2 minutes). To turn stall 
detection
+  off and keep only the total deadline, set it equal to 
`totalTaskTimeoutMillis`.
+  Don't use `0` (rejected when the total is positive) or `Long.MAX_VALUE` (it 
also
+  removes the pipes client's backstop for a wedged server).
 
 * **Per-parser timeouts** (e.g., `tesseract-ocr-parser.timeoutMillis`) -- How 
long may
   *one call* to that parser's external process or service take.
diff --git a/tika-core/src/main/java/org/apache/tika/config/ParseTimeout.java 
b/tika-core/src/main/java/org/apache/tika/config/ParseTimeout.java
index df95726f46..3769b3779d 100644
--- a/tika-core/src/main/java/org/apache/tika/config/ParseTimeout.java
+++ b/tika-core/src/main/java/org/apache/tika/config/ParseTimeout.java
@@ -81,8 +81,7 @@ public class ParseTimeout implements TransientParseState {
      * immediately). A progress timeout of zero with a <em>positive</em> total 
is rejected:
      * it is never intended and would fire the stall detector immediately, 
killing every task
      * despite the remaining total budget. A progress timeout at or above a 
positive total is
-     * accepted but logged, since the stall detector could then never fire 
before the total
-     * deadline.
+     * accepted and disables the stall detector.
      *
      * @throws IllegalArgumentException if either limit is negative, or the 
progress timeout is
      *         zero while the total is positive
@@ -101,10 +100,6 @@ public class ParseTimeout implements TransientParseState {
                     + "totalTaskTimeoutMillis (" + total + ") would kill every 
task immediately; "
                     + "use a positive progress timeout");
         }
-        if (total > 0 && progress >= total) {
-            LOG.warn("progressTimeoutMillis ({}) >= totalTaskTimeoutMillis 
({}) -- the stall " +
-                    "detector can never fire before the total deadline does", 
progress, total);
-        }
         if (total > 0 && total < 1000) {
             LOG.warn("totalTaskTimeoutMillis ({}) is under one second -- this 
is often a " +
                     "seconds-vs-milliseconds mistake in the configuration", 
total);
diff --git a/tika-core/src/main/java/org/apache/tika/config/TimeoutLimits.java 
b/tika-core/src/main/java/org/apache/tika/config/TimeoutLimits.java
index 0c20d1e92a..90490744da 100644
--- a/tika-core/src/main/java/org/apache/tika/config/TimeoutLimits.java
+++ b/tika-core/src/main/java/org/apache/tika/config/TimeoutLimits.java
@@ -18,6 +18,9 @@ package org.apache.tika.config;
 import java.io.Serializable;
 import java.util.Objects;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import org.apache.tika.annotation.TikaComponent;
 import org.apache.tika.exception.TikaConfigException;
 import org.apache.tika.parser.ParseContext;
@@ -30,7 +33,9 @@ import org.apache.tika.parser.ParseContext;
  *       any embedded documents it recurses into
  *       (default: 3,600,000 ms = 1 hour)</li>
  *   <li>{@code progressTimeoutMillis} — bounds time since the last progress 
update;
- *       catches infinite loops and hung processes (default: 120,000 ms = 2 
minutes)</li>
+ *       catches infinite loops and hung processes (default: 120,000 ms = 2 
minutes).
+ *       Set it equal to {@code totalTaskTimeoutMillis} to disable stall 
detection and keep
+ *       only the total deadline; {@code 0} is rejected when the total is 
positive.</li>
  *   <li>{@code throwOnDeadline} — whether reaching the total timeout 
mid-parse throws
  *       (via {@link org.apache.tika.exception.EmbeddedLimitReachedException}) 
instead of
  *       skipping remaining embedded documents and returning content extracted 
so far
@@ -63,6 +68,8 @@ public class TimeoutLimits implements Serializable, 
Initializable {
 
     private static final long serialVersionUID = 2L;
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(TimeoutLimits.class);
+
     public static final long DEFAULT_TOTAL_TASK_TIMEOUT_MILLIS = 3_600_000L;
     public static final long DEFAULT_PROGRESS_TIMEOUT_MILLIS = 120_000L;
 
@@ -148,6 +155,12 @@ public class TimeoutLimits implements Serializable, 
Initializable {
                     + "totalTaskTimeoutMillis (" + totalTaskTimeoutMillis
                     + ") would kill every task immediately; use a positive 
progress timeout");
         }
+        // equal is the documented way to disable stall detection, so only 
warn above it
+        if (totalTaskTimeoutMillis > 0 && progressTimeoutMillis > 
totalTaskTimeoutMillis) {
+            LOG.warn("progressTimeoutMillis ({}) > totalTaskTimeoutMillis ({}) 
-- the stall "
+                    + "detector can never fire; set them equal to disable it 
deliberately",
+                    progressTimeoutMillis, totalTaskTimeoutMillis);
+        }
     }
 
     /**
diff --git 
a/tika-core/src/test/java/org/apache/tika/config/TimeoutLimitsTest.java 
b/tika-core/src/test/java/org/apache/tika/config/TimeoutLimitsTest.java
index ab3f59f8c6..c79404bb4e 100644
--- a/tika-core/src/test/java/org/apache/tika/config/TimeoutLimitsTest.java
+++ b/tika-core/src/test/java/org/apache/tika/config/TimeoutLimitsTest.java
@@ -44,4 +44,12 @@ public class TimeoutLimitsTest {
         assertDoesNotThrow(new TimeoutLimits(0, 0)::initialize);
         assertDoesNotThrow(new TimeoutLimits()::initialize);
     }
+
+    /** progress == total is the supported way to disable stall detection. */
+    @Test
+    public void testProgressEqualToTotalIsValid() {
+        TimeoutLimits limits = new TimeoutLimits(60_000, 60_000);
+        assertDoesNotThrow(limits::initialize);
+        assertDoesNotThrow(() -> ParseTimeout.start(limits));
+    }
 }

Reply via email to