Skip to content

python-apiserver-client: retain job error type and metadata - #5333

Open
git-jxj wants to merge 5 commits into
kuberay-project:masterfrom
git-jxj:git-jxj/fix-python-apiserver-job-info
Open

git-jxj wants to merge 5 commits into
kuberay-project:masterfrom
git-jxj:git-jxj/fix-python-apiserver-job-info

Conversation

@git-jxj

@git-jxj git-jxj commented Sep 22, 2026 •

Copy link
Copy Markdown

Why are these changes needed?

get_job_info and list_job_info lose the job's error type and user metadata because RayJobInfo reads ErrorType and Metadata, while the API server returns errorType and metadata.

Read the API field names and cover populated and absent optional fields in the existing test_submission. This branch is synchronized with current master.

Related issue number

Discovered while checking the Python client against the job submission API's JSON contract.

Labels

  • If this PR has user-facing changes that require documentation updates at release time, I have added the doc-updates-required label.
  • If this PR contains breaking changes, I have added the breaking-change label.

AI assistance

Yes. AI assisted with implementation and testing.

Checks

  • I've made sure the tests are passing.
  • Testing Strategy
    • Unit tests
    • Manual tests

The same test_submission regression fails against master (1 failed) and passes with this change (1 passed). The parameter suite reports:

Client Result
Master (3ec5cbb8) 9 passed, 1 failed, 0 skipped
This change 9 passed, 1 failed, 0 skipped

The remaining test_templates failure also occurs on unchanged master (3ec5cbb8): template serialization and decoding disagree on the extended-resources field. The before/after runs report the same failed assertion.

Manual test instructions

Built the API server and operator from this branch and used a real Ray 2.55.0 head. Submitted a job that exits with code 17 and user metadata, waited for FAILED, then read that same job through both get_job_info and list_job_info.

Both public methods returned:

Client error_type metadata
Master (3ec5cbb8) None None
This change JOB_ENTRYPOINT_COMMAND_ERROR {"case": "field-retention", "owner": "pr5333"}

@machichima

Copy link
Copy Markdown
Collaborator

@cursor review

@cursor cursor Bot 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 85e6ecc. Configure here.

Comment on lines +121 to +122
self.error_type = dct.get("errorType", dct.get("ErrorType"))
self.metadata = dct.get("metadata", dct.get("Metadata"))

@justinyeh1995 justinyeh1995 Sep 29, 2026 •

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.

Curious why we should keep the dct.get("ErrorType") & dct.get("Metadata") fallbacks.
Both get_job_info and list_job_info build RayJobInfo from the API server response, which is always camelCase (errorType / metadata), so the PascalCase keys never appear in the response.
I think it makes more sense to default to None

Suggested change
self.error_type = dct.get("errorType", dct.get("ErrorType"))
self.metadata = dct.get("metadata", dct.get("Metadata"))
self.error_type = dct.get("errorType", None)
self.metadata = dct.get("metadata", None)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the feedback. I removed both PascalCase fallbacks. The API gateway marshals these proto messages with UseProtoNames: false, so error_type is exposed as errorType; metadata stays lowercase.

from python_apiserver_client.params import RayJobInfo


@pytest.mark.parametrize("error_key,metadata_key", [("errorType", "metadata"), ("ErrorType", "Metadata")])

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.

The ("ErrorType", "Metadata") test case can be dropped too.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed; I removed the ("ErrorType", "Metadata") parameter case. The test now covers the API server field names and the absent optional fields.

assert info.metadata is None


@pytest.mark.parametrize("list_jobs", [False, True])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A small optional suggestion: could we add explicit IDs so the pytest output shows the method instead of showing [False] / [True]? I tried this locally and all four tests still pass.

Suggested change
@pytest.mark.parametrize("list_jobs", [False, True])
@pytest.mark.parametrize(
"list_jobs", [False, True], ids=["get_job_info", "list_job_info"]
)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added get_job_info and list_job_info IDs. All four job-info tests pass.

@justinyeh1995 justinyeh1995 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.

Thanks for the contribution. "Read the API's field names while retaining compatibility with the previously accepted capitalized keys." in the pr description no longer holds. Can you update it to "Read the API's camelCase field names."?

@git-jxj

git-jxj commented Oct 1, 2026

Copy link
Copy Markdown
Author

@justinyeh1995 Updated the description to "Read the API's camelCase field names." and corrected the test count to four.

@git-jxj

git-jxj commented Oct 1, 2026

Copy link
Copy Markdown
Author

The History Server E2E job on d1ab78d4 fails during MinIO setup: TestCollector and TestHistoryServer both time out after 300 seconds waiting for MinIO pods to be ready at historyserver/test/support/s3.go:160. This job runs Go history-server tests; this PR only changes the Python apiserver client and its tests. Could someone with Buildkite access check MinIO readiness and retry this job?

@justinyeh1995

justinyeh1995 commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

The History Server E2E job on d1ab78d4 fails during MinIO setup: TestCollector and TestHistoryServer both time out after 300 seconds waiting for MinIO pods to be ready at historyserver/test/support/s3.go:160. This job runs Go history-server tests; this PR only changes the Python apiserver client and its tests. Could someone with Buildkite access check MinIO readiness and retry this job?

Have you tried rebasing to the latest commit on remote master?
See
#5342
#5357

Signed-off-by: git-jxj <65210887+git-jxj@users.noreply.github.com>
@git-jxj
git-jxj force-pushed the git-jxj/fix-python-apiserver-job-info branch from d1ab78d to 1ee686b Compare October 2, 2026 05:04
@git-jxj

git-jxj commented Oct 2, 2026

Copy link
Copy Markdown
Author

@justinyeh1995 Rebased onto the latest master (9dc55272); the new head is 1ee686bf and Buildkite build 17382 has started.

This includes #5342, which disables the History Server E2E step with if: "false". The step remains disabled on this branch; this rebase does not establish a passing History Server E2E result. #5357 is still open; its RustFS changes are not included.

All four job-info regression tests and the applicable file checks pass after the rebase. The unrelated test_templates serialization failure also reproduces on the unchanged latest master.

@justinyeh1995 justinyeh1995 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.

Thanks. LGTM. cc @machichima to take a look if you have the time.

@szaher szaher 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.

/lgtm

@git-jxj

git-jxj commented Oct 15, 2026

Copy link
Copy Markdown
Author

Could a maintainer approve the workflows awaiting authorization for head 1ee686bfd79ee32b977f81dfaec6f9bf413854a1: Go-build-and-test, Helm, operator-consistency-check? These runs have not started their jobs yet. Thank you.

@400Ping

400Ping commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Done

@machichima machichima left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you please paste the manual test result (before / after this change) in the PR description against the real API server?

Also, please run the unit test locally and paste the result here, since we do not have CI for it yet.

Thank you!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Instead of creating a new test file, could we add assertions under test_submission in clients/python-apiserver-client/test/api_params_test.py?

def test_submission():
yaml = """
pip:
- requests==2.26.0
- pendulum==2.1.2
env_vars:
counter_name: test_counter
"""
request = RayJobRequest(entrypoint="python /home/ray/samples/sample_code.py", runtime_env=yaml, num_cpu=0.5)
print(f"job request: {request.to_string()}")
request_json = json.dumps(request.to_dict())
print(f"request JSON: {request_json}")
info_json = """
{
"entrypoint":"python /home/ray/samples/sample_code.py",
"jobId":"02000000",
"submissionId":"raysubmit_KWZLwme56esG3Wcr",
"status":"SUCCEEDED",
"message":"Job finished successfully.",
"startTime":"1699442662879",
"endTime":"1699442682405",
"runtimeEnv":{
"env_vars":"map[counter_name:test_counter]",
"pip":"[requests==2.26.0 pendulum==2.1.2]"
}
}
"""
job_info = RayJobInfo(json.loads(info_json))
print(job_info.to_string())

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Moved the assertions into api_params_test.py::test_submission and removed the separate test file.

@git-jxj

git-jxj commented Oct 26, 2026

Copy link
Copy Markdown
Author

@machichima I tested this against a real API server with a Ray 2.55.0 cluster. For the same failed job, both get_job_info and list_job_info returned None for the two fields before the fix and preserved JOB_ENTRYPOINT_COMMAND_ERROR and the submitted metadata afterward. I've added the before/after results to the PR description.

The local unit test results are:

test_submission: 1 passed
api_params_test.py: 1 failed, 9 passed (test_templates)

The same test_templates failure reproduces on the unchanged base (9dc55272): the template round trip drops extended_resources because serialization and decoding use different keys.

git-jxj and others added 4 commits October 28, 2026 13:11
Signed-off-by: xinjun.jiang <xinjun.jiang@daocloud.io>
Signed-off-by: xinjun.jiang <xinjun.jiang@daocloud.io>
Signed-off-by: xinjun.jiang <xinjun.jiang@daocloud.io>
Signed-off-by: xinjun.jiang <xinjun.jiang@daocloud.io>
@git-jxj
git-jxj force-pushed the git-jxj/fix-python-apiserver-job-info branch from c661b87 to 6244b60 Compare October 28, 2026 06:22

This branch has not been deployed

No deployments
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.

6 participants