Skip to content

TEZ-4733: Fix flaky TestHistoryParser.testParserWithSuccessfulJob - #519

Open
maheshrajus wants to merge 2 commits into
apache:masterfrom
maheshrajus:TEZ-4733
Open

TEZ-4733: Fix flaky TestHistoryParser.testParserWithSuccessfulJob#519
maheshrajus wants to merge 2 commits into
apache:masterfrom
maheshrajus:TEZ-4733

Conversation

@maheshrajus

Copy link
Copy Markdown
Contributor

Problem

org.apache.tez.history.TestHistoryParser.testParserWithSuccessfulJob fails intermittently with:

 JSONException: A JSONObject text must begin with '{' at character 0 of at ATSFileParser.readJson(ATSFileParser.java:181) at ATSFileParser.parseATSZipFile(...) at ATSFileParser.getDAGData(...) 

Root cause

After the DAG client returns, ATSHistoryLoggingService still has history events in an async queue that must be
flushed to the timeline server. The test previously called ATSImportTool.process(...) immediately, so under load the
download could race the timeline write path — producing a zip whose entries were empty/whitespace, which then failed JSON parsing with the misleading "must begin with {" error.
A fixed Thread.sleep(10000) was already present before the SimpleHistory parse path (as a workaround for the same class of race), but there was no equivalent guard for the ATS parse path.

Changes

  1. ATSFileParser:
    - skip empty/whitespace zip entries with a WARN; enrich JSON parse errors with the offending entry name + payload snippet.
  2. TestHistoryParser:
    -replaced the unguarded ATS export+parse with a retry loop that only accepts a DagInfo with ≥2
    vertices, tasks, and attempts.
    -replaced the fixed Thread.sleep(10000) before SimpleHistory parse with a
    poll-until-file-size-stable.
  3. New TestATSFileParser:
    -New tests added that checks (empty entry skipped, malformed entry names itself in the error).

@tez-yetus

Copy link
Copy Markdown

💔 -1 overall

VoteSubsystemRuntimeLogfileComment
+0 🆗reexec11m 18sDocker mode activated.
_ Prechecks _
+1 💚dupname0m 0sNo case conflicting files found.
+0 🆗detsecrets0m 0sdetect-secrets was not available.
+1 💚@author0m 0sThe patch does not contain any @author tags.
+1 💚test4tests0m 0sThe patch appears to include 2 new or modified test files.
_ master Compile Tests _
+1 💚mvninstall4m 46smaster passed
+1 💚compile4m 1smaster passed
+1 💚checkstyle0m 32smaster passed
+1 💚javadoc0m 27smaster passed
+0 🆗spotbugs0m 49stez-plugins/tez-history-parser in master has 21 extant spotbugs warnings.
_ Patch Compile Tests _
+1 💚mvninstall3m 46sthe patch passed
+1 💚codespell1m 37sNo new issues.
+1 💚compile4m 2sthe patch passed
+1 💚javac4m 2sthe patch passed
+1 💚blanks0m 0sThe patch has no blanks issues.
+1 💚checkstyle0m 26stez-plugins/tez-history-parser: The patch generated 0 new + 17 unchanged - 1 fixed = 17 total (was 18)
+1 💚javadoc0m 26sthe patch passed
+1 💚spotbugs0m 59sthe patch passed
_ Other Tests _
-1 ❌unit76m 51s/patch-unit-root.txtroot in the patch passed.
+1 💚asflicense0m 29sThe patch does not generate ASF License warnings.
112m 4s
ReasonTests
Failed junit teststez.test.TestAMRecovery
SubsystemReport/Notes
DockerClientAPI=1.55 ServerAPI=1.55 base: https://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/1/artifact/out/Dockerfile
Optional Testsdupname compile unit asflicense javac javadoc spotbugs checkstyle codespell detsecrets
unameLinux 27b643db62b8 5.15.0-181-generic #191-Ubuntu SMP Fri May 22 19:09:02 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Build toolmaven
Personalitytez-personality.sh
git revisionmaster / 4bccf3a
Default JavaEclipse Adoptium-21.0.11+10-LTS
Test Resultshttps://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/1/testReport/
Max. process+thread count1462 (vs. ulimit of 5500)
modulesC: tez-plugins/tez-history-parser U: tez-plugins/tez-history-parser
Console outputhttps://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/1/console
versionsgit=2.43.0 maven=3.9.15 spotbugs=4.9.3 codespell=2.4.1
Powered byApache Yetus 0.15.1 https://yetus.apache.org

This message was automatically generated.

@tez-yetus

Copy link
Copy Markdown

🎊 +1 overall

VoteSubsystemRuntimeLogfileComment
+0 🆗reexec9m 24sDocker mode activated.
_ Prechecks _
+1 💚dupname0m 0sNo case conflicting files found.
+0 🆗detsecrets0m 0sdetect-secrets was not available.
+1 💚@author0m 0sThe patch does not contain any @author tags.
+1 💚test4tests0m 0sThe patch appears to include 2 new or modified test files.
_ master Compile Tests _
+1 💚mvninstall5m 3smaster passed
+1 💚compile4m 0smaster passed
+1 💚checkstyle0m 29smaster passed
+1 💚javadoc0m 25smaster passed
+0 🆗spotbugs0m 50stez-plugins/tez-history-parser in master has 21 extant spotbugs warnings.
_ Patch Compile Tests _
+1 💚mvninstall4m 1sthe patch passed
+1 💚codespell1m 46sNo new issues.
+1 💚compile3m 59sthe patch passed
+1 💚javac3m 59sthe patch passed
+1 💚blanks0m 0sThe patch has no blanks issues.
+1 💚checkstyle0m 24stez-plugins/tez-history-parser: The patch generated 0 new + 17 unchanged - 1 fixed = 17 total (was 18)
+1 💚javadoc0m 24sthe patch passed
+1 💚spotbugs1m 0sthe patch passed
_ Other Tests _
+1 💚unit75m 40sroot in the patch passed.
+1 💚asflicense0m 28sThe patch does not generate ASF License warnings.
109m 38s
SubsystemReport/Notes
DockerClientAPI=1.55 ServerAPI=1.55 base: https://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/2/artifact/out/Dockerfile
Optional Testsdupname compile unit asflicense javac javadoc spotbugs checkstyle codespell detsecrets
unameLinux 0192f1c74d85 5.15.0-177-generic #187-Ubuntu SMP Sat Apr 11 22:54:33 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Build toolmaven
Personalitytez-personality.sh
git revisionmaster / 4bccf3a
Default JavaEclipse Adoptium-21.0.11+10-LTS
Test Resultshttps://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/2/testReport/
Max. process+thread count1439 (vs. ulimit of 5500)
modulesC: tez-plugins/tez-history-parser U: tez-plugins/tez-history-parser
Console outputhttps://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/2/console
versionsgit=2.43.0 maven=3.9.15 spotbugs=4.9.3 codespell=2.4.1
Powered byApache Yetus 0.15.1 https://yetus.apache.org

This message was automatically generated.

@maheshrajus

Copy link
Copy Markdown
ContributorAuthor

@abstractdog Could you please review and approve the PR at your convenience?
Thank you !

//the expected DAG (two vertices, non-empty vertices/tasks). Under load the AM's async
//flush and the timeline server's write path can race the export, leaving empty/partial
//entities in the zip. Before TEZ-4733 that produced a misleading
//"A JSONObject text must begin with '{'" JSONException at parse time.

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.

this is not needed: "Before TEZ-4733 that produced a misleading
//"A JSONObject text must begin with '{'" JSONException at parse time."

lastError = e;
}
if (attempt < maxAttempts) {
Thread.sleep(delayMs);

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.

I think it's overkill to provide delayMs and maxAttempts at the same time
use a reasonable delayMs, and let the user of this method define maxAttempts accordingly

FileSystem hfs = historyPath.getFileSystem(conf);
long deadline = System.currentTimeMillis() + timeoutMs;
long lastLen = -1L;
while (System.currentTimeMillis() < deadline) {

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.

use monothonic time

+ SIMPLE_HISTORY_DIR + HISTORY_TXT + "."
+ applicationAttemptId);
FileSystem hfs = historyPath.getFileSystem(conf);
long deadline = System.currentTimeMillis() + timeoutMs;

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.

use monothonic time

Comment on lines +103 to +106
assertTrue(msg.contains(DAG_ID),
"Error should name the offending zip entry, got: " + msg);
assertTrue(msg.contains("<html>"),
"Error should include a snippet of the offending payload, got: " + msg);

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.

no need for the line breaks I believe

Comment on lines +213 to +219
//Read entire content to memory so we can pass entry name into error messages
final NonSyncByteArrayOutputStream bout = new NonSyncByteArrayOutputStream();
IOUtils.copy(inputStream, bout);
JSONObject jsonObject = readJson(bout.toByteArray(), zipEntry.getName());
if (jsonObject == null) {
continue;
}

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.

I think the all the mess with NonSyncByteArrayOutputStream can still go to the readJson, right?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed

return new JSONObject(new String(bout.toByteArray(), "UTF-8"));
/**
* Parse the raw payload of a single zip entry as JSON.
* Returns null if the payload is empty or blank — callers should skip such entries.

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.

empty or blank? what's the difference in this sense?
also, if there is a javadoc, it should state that a JSONException is thrown in case of parse errors

Comment on lines +109 to +110
private record ZipContent(String name, String payload) {
}

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.

what is the record for?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@abstractdog
It's just a lightweight data holder for writeZip(...) that lets each test declare its entries inline as (name, payload) pairs.
I used a record since it's pure data with no behavior, but I'm happy to switch to a per-entry writeEntry(zos, name, payload) helper if we'd prefer not to introduce a new type.

@tez-yetus

Copy link
Copy Markdown

🎊 +1 overall

VoteSubsystemRuntimeLogfileComment
+0 🆗reexec0m 39sDocker mode activated.
_ Prechecks _
+1 💚dupname0m 0sNo case conflicting files found.
+0 🆗detsecrets0m 0sdetect-secrets was not available.
+1 💚@author0m 0sThe patch does not contain any @author tags.
+1 💚test4tests0m 0sThe patch appears to include 2 new or modified test files.
_ master Compile Tests _
+1 💚mvninstall4m 50smaster passed
+1 💚compile3m 59smaster passed
+1 💚checkstyle0m 30smaster passed
+1 💚javadoc0m 28smaster passed
+0 🆗spotbugs0m 51stez-plugins/tez-history-parser in master has 21 extant spotbugs warnings.
_ Patch Compile Tests _
+1 💚mvninstall3m 41sthe patch passed
+1 💚codespell1m 35sNo new issues.
+1 💚compile4m 3sthe patch passed
+1 💚javac4m 3sthe patch passed
+1 💚blanks0m 0sThe patch has no blanks issues.
+1 💚checkstyle0m 25stez-plugins/tez-history-parser: The patch generated 0 new + 16 unchanged - 2 fixed = 16 total (was 18)
+1 💚javadoc0m 26sthe patch passed
+1 💚spotbugs0m 59sthe patch passed
_ Other Tests _
+1 💚unit75m 17sroot in the patch passed.
+1 💚asflicense0m 30sThe patch does not generate ASF License warnings.
99m 46s
SubsystemReport/Notes
DockerClientAPI=1.55 ServerAPI=1.55 base: https://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/3/artifact/out/Dockerfile
Optional Testsdupname compile unit asflicense javac javadoc spotbugs checkstyle codespell detsecrets
unameLinux 997c08e22f13 5.15.0-181-generic #191-Ubuntu SMP Fri May 22 19:09:02 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Build toolmaven
Personalitytez-personality.sh
git revisionmaster / d348bf1
Default JavaEclipse Adoptium-21.0.11+10-LTS
Test Resultshttps://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/3/testReport/
Max. process+thread count1539 (vs. ulimit of 5500)
modulesC: tez-plugins/tez-history-parser U: tez-plugins/tez-history-parser
Console outputhttps://ci-hadoop.apache.org/job/tez-multibranch/job/PR-519/3/console
versionsgit=2.43.0 maven=3.9.15 spotbugs=4.9.3 codespell=2.4.1
Powered byApache Yetus 0.15.1 https://yetus.apache.org

This message was automatically generated.

@maheshrajus

Copy link
Copy Markdown
ContributorAuthor

@abstractdog Fixed your review comments. Could you please check and approve the PR at your convenience?
Thank you !

@maheshrajus

Copy link
Copy Markdown
ContributorAuthor

@abstractdog Could you please check and approve the PR at your convenience? Thank you !

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Improves history parser resilience against incomplete asynchronous history writes.

Changes:

  • Skips blank ATS zip entries and improves malformed JSON diagnostics.
  • Adds ATS retry and SimpleHistory readiness polling.
  • Adds ATS parser regression tests.

Reviewed changes

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

FileDescription
TestHistoryParser.javaAdds retry and readiness helpers.
TestATSFileParser.javaTests blank and malformed entries.
ATSFileParser.javaHandles blank entries and enriches errors.

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

try {
// Fresh download every attempt — ATSImportTool overwrites the zip.
int result = ATSImportTool.process(args);
assertEquals(0, result);
Comment on lines +304 to +305
if (len > 0 && len == lastLen) {
return;
Comment on lines +222 to +223
if (jsonObject == null) {
continue;
Sign up for freeto 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.

4 participants

@maheshrajus@tez-yetus@abstractdog