feat(transform): support empty data flow and batch temporary tables#9
Open
ChihuaYing wants to merge 2 commits into
Open
feat(transform): support empty data flow and batch temporary tables#9ChihuaYing wants to merge 2 commits into
ChihuaYing wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
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.
This PR enhances the Transform pipeline to correctly support empty inputs/outputs, improve scheduled batch isolation, and propagate Python/write failures as job failures with queryable error details.
Changes:
- Add job failure error message propagation through Thrift/Session APIs and expose root cause text.
- Remove mutex-based async waiting and make Python execution + result writing fail-fast/synchronous; support header-only empty BatchData flow through transforms/SQL.
- Expand integration tests and add Python transformer fixtures to cover empty/invalid outputs, scheduled batch isolation, and temp-table SQL consumption.
Reviewed changes
Copilot reviewed 37 out of 37 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| thrift/src/main/thrift/rpc.thrift | Adds optional errorMessage field to transform job status response. |
| session_py/iginx/iginx_pyclient/thrift/rpc/ttypes.py | Updates generated Python Thrift types to include errorMessage. |
| session/src/main/java/cn/edu/tsinghua/iginx/session/Session.java | Adds queryTransformJobErrorMessage() API for clients. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/utils/Mutex.java | Removes mutex utility no longer used for stage coordination. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/pojo/Job.java | Adds batch-python-to-SQL temp table wiring via outputPrefix. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/exec/tools/ExecutionMetaManager.java | Adds temp-table meta cleanup and case-insensitive replacement behavior. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/exec/TransformJobManager.java | Adds server-side error message extraction for failed jobs. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/exec/StreamStageRunner.java | Resets writers per trigger and returns empty RowStream when SQL has no result stream. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/exec/ScheduledJob.java | Clears temp-table meta per trigger and stabilizes cleanup logging. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/exec/JobValidationChecker.java | Removes “last SQL must be SELECT/SHOW” restriction to allow empty/no-result flows. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/exec/BatchStageRunner.java | Removes mutex waiting; resets writers/input buffers between scheduled runs. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/driver/PemjaWorker.java | Makes Python processing throw TransformException and validates/propagates invalid output. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/driver/IPCWorker.java | Updates exception type to TransformException for writer failures. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/SplitReader.java | Ensures an empty batch (header-only) is emitted once for empty inputs. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/RowStreamReader.java | Ensures an empty batch (header-only) is emitted once for empty SQL results. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/PemjaWriter.java | Updates writer signature to throw TransformException. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/PemjaReader.java | Strictly validates Python return format, supports header-only empty tables, and enforces column type consistency. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/LogWriter.java | Skips writes for empty batches to treat header-only output as empty export. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/IginXWriter.java | Skips writes for empty batches to avoid creating physical temp columns on empty output. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/FileAppendWriter.java | Makes file export fail-fast on IO errors and batches file writes per batch. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/Exporter.java | Removes mutex exposure from exporter interface. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/ExportWriter.java | Removes mutex coordination and propagates TransformException from writes. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/data/BatchData.java | Adds isEmpty() helper for header-only empty-batch handling. |
| core/src/main/java/cn/edu/tsinghua/iginx/transform/api/Writer.java | Changes writeBatch to throw TransformException. |
| core/src/main/java/cn/edu/tsinghua/iginx/IginxWorker.java | Populates errorMessage in job status response when present. |
| test/src/test/java/cn/edu/tsinghua/iginx/integration/func/udf/TransformIT.java | Adds extensive IT coverage for empty flows, invalid outputs, temp tables, and scheduled isolation. |
| test/src/test/resources/transform/transformer_none.py | Adds invalid-output transformer fixture returning None. |
| test/src/test/resources/transform/transformer_empty_list.py | Adds invalid-output transformer fixture returning []. |
| test/src/test/resources/transform/transformer_empty_input_pass.py | Adds transformer fixture that accepts header-only input. |
| test/src/test/resources/transform/transformer_empty_input_fail.py | Adds transformer fixture that errors on header-only input. |
| test/src/test/resources/transform/transformer_empty_input_emit.py | Adds transformer fixture that emits data on empty input. |
| test/src/test/resources/transform/transformer_empty_header.py | Adds invalid-output transformer fixture returning [[]]. |
| test/src/test/resources/transform/transformer_empty.py | Adds transformer fixture returning header-only output. |
| test/src/test/resources/transform/transformer_bad_value.py | Adds invalid-output transformer fixture returning unsupported value type. |
| test/src/test/resources/transform/transformer_bad_row_type.py | Adds invalid-output transformer fixture returning non-list data row. |
| test/src/test/resources/transform/transformer_bad_row.py | Adds invalid-output transformer fixture returning wrong row length. |
| test/src/test/resources/transform/transformer_bad_header.py | Adds invalid-output transformer fixture returning non-string header. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+318
to
+334
| while (!jobState.equals(JobState.JOB_CLOSED) | ||
| && !jobState.equals(JobState.JOB_FAILED) | ||
| && !jobState.equals(JobState.JOB_FINISHED) | ||
| && timeout > 0) { | ||
| Thread.sleep(500); | ||
| timeout -= 500; | ||
| jobState = session.queryTransformJobStatus(jobId); | ||
| } | ||
| assertTrue(scenario + " should fail instead of timing out", timeout > 0); | ||
| assertEquals(scenario + " should fail", JobState.JOB_FAILED, jobState); | ||
| if (expectedErrorMessage != null) { | ||
| String errorMessage = session.queryTransformJobErrorMessage(jobId); | ||
| assertNotNull(scenario + " should expose an error message", errorMessage); | ||
| assertTrue( | ||
| scenario + " should report: " + expectedErrorMessage, | ||
| errorMessage.contains(expectedErrorMessage)); | ||
| } |
Comment on lines
+79
to
+84
| String replacement = | ||
| metaThreadLocal.get().entrySet().stream() | ||
| .filter(entry -> entry.getKey().equalsIgnoreCase(matched)) | ||
| .map(Map.Entry::getValue) | ||
| .findFirst() | ||
| .orElse(matched); |
Comment on lines
+352
to
+363
| public String queryJobErrorMessage(long jobId) { | ||
| Job job = jobMap.get(jobId); | ||
| if (job == null || job.getException() == null) { | ||
| return null; | ||
| } | ||
|
|
||
| Throwable cause = job.getException(); | ||
| while (cause.getCause() != null) { | ||
| cause = cause.getCause(); | ||
| } | ||
| return cause.getMessage(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
本次功能与修复
CollectionWriter缓冲,避免下一轮嵌套旧PemjaWriter或混入上一轮数据。Mutex的异步等待,改为同步传播 Python 调用及写入异常,修复空输出时等待不到解锁而死锁、并发文件写入可能丢数据的问题。BatchData继续传入用户 Transform。[header]:可继续传给下游 Transform;接 SQL 时不创建物理临时列,查询不存在的临时路径得到空结果并正常完成。None、空列表、非法/空表头、非列表数据行、列数不一致、非法值类型及列内类型不一致;合法空表保持兼容。Batch Python(outputPrefix) -> SQL,与原 Stream 链路一致写入 IginX 临时表;完善临时表别名的每轮创建、大小写替换、清理及 Quartz 线程复用清理。SELECT/SHOW开头的校验;无结果流的成功 SQL 会作为空输入继续传递。IginXWriter生成的非确定时间键,断言其为合法long,并验证后续计算列55,55,65。新增/调整测试
TransformIT增加并统一命名、标注流水线的测试,覆盖:None、空列表、坏表头、坏数据行、类型错误等 7 类非法输出,并断言具体错误信息。SQL(empty) -> Transform(empty) -> Transform(empty)的空数据传播。新增测试脚本位于
test/src/test/resources/transform