Skip to content

Normalize Skypilot managed job ids to int (#481) - #588

Open
CodersAcademy006 wants to merge 1 commit into
NVIDIA-NeMo:mainfrom
CodersAcademy006:fix/481-skypilot-jobs-list-job-id
Open

Normalize Skypilot managed job ids to int (#481)#588
CodersAcademy006 wants to merge 1 commit into
NVIDIA-NeMo:mainfrom
CodersAcademy006:fix/481-skypilot-jobs-list-job-id

Conversation

@CodersAcademy006

Copy link
Copy Markdown
Contributor

Closes #481.

Root cause

SkyPilot's managed-jobs SDK returns a list of job ids. From sky/jobs/client/sdk.py in skypilot 0.12.3:

def launch(...) -> server_common.RequestId[Tuple[Optional[List[int]],
                                                 Optional['backends.ResourceHandle']]]:

SkypilotJobsExecutor.launch passed that value straight through while its own annotation promised tuple[Optional[int], ...], and the scheduler builds the app id by interpolation (torchx_backend/schedulers/skypilot_jobs.py):

app_id = f"{handle.get_cluster_name()}___{task.name}___{job_id}"

So the app id became cluster___task___[1], and the very next line, SkypilotJobsExecutor.status(app_id=app_id), reached parse_app and died on int('[1]'). The job itself was already accepted by SkyPilot, so as @jesintharnold reported the managed job keeps running while nemo_run loses the handle, taking nemo experiment status and nemo experiment logs with it.

Change

One helper, _as_job_id, used from both ends so the two sites cannot drift:

  • launch unwraps the single-element list, restoring the Optional[int] contract its signature already claimed. A list with more than one id asserts with the value in the message rather than silently taking the first.
  • parse_app accepts the bracketed form, so app ids already persisted in experiment metadata by an affected run remain readable instead of requiring a re-submit. cleanup, logs, cancel and status all route through parse_app, so they are fixed by the same change.

SkypilotExecutor (the non-managed path) is deliberately untouched: sky/client/sdk.py's launch returns Tuple[Optional[int], ...], so it never had this bug.

Tests

Two in test/core/execution/test_skypilot_jobs.py:

  • test_launch_normalizes_list_job_id mocks the SDK the way it actually behaves, returning ([1], handle), and asserts the id comes back as 1 and then survives a round trip through the same f"..." app-id shape the scheduler builds. The existing test_launch mocked (123, handle), an int, which is why CI never saw this.
  • test_parse_app_legacy_list_job_id pins the recovery path for app ids already written as ___[123].

Verified locally with skypilot 0.12.3 installed: 32 passed in test/core/execution/test_skypilot_jobs.py, and reverting only the nemo_run/ half fails exactly the two new tests. ruff format --diff and ruff check clean.

@ko3n1g this one has been open since May 10 with no reviewer and it silently orphans running jobs, so it may be worth prioritising over the other two SkyPilot reports from the same user (#482, #483), which need real cluster access to settle.

`sky.jobs.client.sdk.launch` returns `Optional[List[int]]`, so
`SkypilotJobsExecutor.launch` handed back `[1]` while its annotation
promised `Optional[int]`. The scheduler interpolates that straight into
`f"{cluster}___{task}___{job_id}"`, so the app id became
`cluster___task___[1]` and `parse_app` died on
`int('[1]')`. The managed job kept running while nemo_run lost the handle,
which also broke `nemo experiment status` and `nemo experiment logs`.

Coerce the id in one place: `launch` unwraps the single-element list, and
`parse_app` accepts the bracketed form so app ids already written to
experiment metadata stay readable. The plain `sky.launch` path used by
SkypilotExecutor returns `Optional[int]` and is untouched.

Closes NVIDIA-NeMo#481

Signed-off-by: Srijan Upadhyay <srjnupadhyay@gmail.com>
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.

SkypilotJobsExecutor crashes after submission when SkyPilot returns job id as [1]

1 participant