[Feature] Stream and paginate persisted task results
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
Research direction
Start with the task-details endpoint, HugeTask.asMap(), the local task-vertex result path, and the distributed HugeTaskResult/~taskresult path. Review the result-storage boundary added in #3060 and the implementation tracked in #3144, then inspect the scheduler SPI and related task API tests. Done means the new result endpoint preserves the existing API while streaming and paging both persisted result forms with the required resource, token, error, and cleanup behavior.
Written by the indexing model from the issue text.
Description
Feature Description
Large asynchronous Gremlin results are persisted as a compressed task-result BLOB. The existing task-details endpoint loads the result into the task object and returns it through HugeTask.asMap(). Even after metadata-only access was added in #3060, a client that actually needs the result still has to request the complete decompressed value. This can create substantial heap pressure and long response times for large persisted results, as seen in #3057 and #3059.
Add a dedicated, read-only endpoint for consuming a persisted task result without materializing a complete decompressed JSON string or Java object tree:
GET /graphspaces/{graphspace}/graphs/{graph}/tasks/{id}/result
The existing GET .../tasks/{id} API and its with_result behavior must remain compatible.
Current and proposed read paths
flowchart LR
Details["GET .../tasks/{id}\nwith_result=true"] --> Task["Load task and full result"]
Task --> Map["HugeTask.asMap()"]
Map --> Existing["Task-details response"]
Result["GET .../tasks/{id}/result"] --> Snapshot["Detached compressed snapshot"]
Snapshot --> Stream["LZ4 stream + JSON token parser"]
Stream --> NewResponse["Raw JSON or logical page"]
For local schedulers, the snapshot comes from the task vertex result property. For distributed schedulers, it comes from the separate HugeTaskResult / ~taskresult vertex introduced by the current result-storage model. The snapshot must be detached before the HTTP callback runs so no graph transaction, vertex iterator, or scheduler thread context is retained by a slow client.
API behavior
| Request | Response |
|---|---|
GET .../tasks/{id}/result |
Streams the original persisted JSON value. |
GET .../tasks/{id}/result?limit=N |
Returns the first logical page. |
GET .../tasks/{id}/result?page=<token> |
Returns the next logical page using an opaque continuation token. |
A paged response uses HugeGraph's existing limit / page convention:
{
"root_type": "array",
"items": [1, 2],
"page": "<opaque token or null>"
}
Top-level arrays are paged by element and top-level objects by member. Object members are represented as key / value items so duplicate JSON keys are not collapsed. Scalars can be streamed in full but are not pageable. limit and page are mutually exclusive, and the terminal page returns "page": null.
The continuation token must be signed and bind the graphspace, graph, task id, result fingerprint, root type, limit, next offset, and expiry. Predictable validation failures must be detected before HTTP 200 is committed. The endpoint should reuse HugeGraph's standard gzip compression and exception / message / cause error envelope.
Resource and consistency requirements
- Only a successfully persisted task result is readable through the new endpoint.
- A changed result must invalidate an older page token instead of continuing over a different snapshot.
- Logical pagination over one BLOB may rescan from the beginning, so page offset, decompressed scan bytes, scan time, active streams, stream duration, and token size/lifetime need explicit limits.
- Client disconnects and slow-reader timeouts must close the parser/decompression stream, restore connection timeout state, and release the active-stream permit.
- Multi-node deployments need a shared page-token secret, with current/previous key support for bounded rotation.
- The scheduler SPI extension must remain compatible with custom schedulers that do not implement result streaming.
Scope and non-goals
This feature changes only the read path. It does not change task-result serialization, storage schema, write limits, or the existing task-details response. The current backend API still returns the compressed BLOB eagerly, so the feature removes the complete decompressed result and object-tree materialization but does not eliminate the in-memory compressed byte[].
Physical chunk storage and random-access page lookup remain follow-up work under #3071. Streaming Gremlin execution and write-time chunk publication also require a separate design because they change transaction, failure, cancellation, and size-limit semantics.
Acceptance criteria
- The existing task-details API remains backward compatible.
- The new endpoint reads both local task-vertex results and distributed
HugeTaskResultresults. - Full-result retrieval does not create a complete decompressed result
Stringor Java object tree. - Array/object pagination follows the
limit/pagecontract and rejects scalar pagination. - Page tokens are signed, route/result-bound, expiring, tamper-resistant, and rotation-aware.
- Predictable errors are returned before response commit; post-commit failures terminate the stream and remain observable.
- Gzip transport, resource budgets, client disconnects, slow readers, metrics, and permit cleanup are covered by tests.
- Memory profiling documents the remaining compressed-BLOB allocation and verifies that the full decompressed result is absent.
Related work
- #3057 and #3059 report task APIs becoming unavailable or timing out after very large task results.
- #3060 added metadata-only task access and separated metadata/result reads; this feature builds on that boundary.
- #3071 tracks physical chunked storage and larger-result follow-up work; this issue deliberately does not close or replace it.
- Implementation: #3144.
- Dominant language
- Java
- Stars
- 3.2k
- Forks
- 637
- Avg merge
- 3d 18h
- Merged PRs (30d)
- 23
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from apache/hugegraph
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
-
Difficulty 3/5 1-2 days Newbie friendliness 64/100
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
Difficulty 5/5 Over a week Newbie friendliness 28/100
All issues in apache/hugegraph
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
checkstyle/test-configs#263 ·
-
bug
Difficulty 1/5 Under an hour Newbie friendliness 90/100
apache/cloudstack#14222 ·
-
[BUG]茶杯方块在取茶时会引发崩溃 Open
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
1.0.0-alpha2 Type/Improvement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
wso2/dpdp-accelerator#272 ·