Skip to content

Commit

Permalink
Implement cancel job operation for CLI
Browse files Browse the repository at this point in the history
This introduces a cancel job operation for CLI that can be used to
cancel a job running in studio.

Command:
`datachain studio cance <JOB_ID`
  • Loading branch information
amritghimire committed Dec 12, 2024
1 parent b67d599 commit 6fce628
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/datachain/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,28 @@ def add_studio_parser(subparsers, parent_parser) -> None:
help="Python package requirement. Can be specified multiple times.",
)

studio_cancel_help = "Cancel a job in Studio"
studio_cancel_description = "This command cancels a job in Studio."

studio_cancel_parser = studio_subparser.add_parser(
"cancel",
parents=[parent_parser],
description=studio_cancel_description,
help=studio_cancel_help,
)

studio_cancel_parser.add_argument(
"job_id",
action="store",
help="The job ID to cancel.",
)
studio_cancel_parser.add_argument(
"--team",
action="store",
default=None,
help="The team to cancel a job for. By default, it will use team from config.",
)


def get_parser() -> ArgumentParser: # noqa: PLR0915
try:
Expand Down
7 changes: 7 additions & 0 deletions src/datachain/remote/studio.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,3 +359,10 @@ def create_job(
"requirements": requirements,
}
return self._send_request("datachain/job", data)

def cancel_job(
self,
job_id: str,
) -> Response[JobData]:
url = f"datachain/job/{job_id}/cancel"
return self._send_request(url, data={}, method="POST")
20 changes: 19 additions & 1 deletion src/datachain/studio.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
)


def process_studio_cli_args(args: "Namespace"):
def process_studio_cli_args(args: "Namespace"): # noqa: PLR0911
if args.cmd == "login":
return login(args)
if args.cmd == "logout":
Expand Down Expand Up @@ -47,6 +47,9 @@ def process_studio_cli_args(args: "Namespace"):
args.req_file,
)

if args.cmd == "cancel":
return cancel_job(args.job_id, args.team)

if args.cmd == "team":
return set_team(args)
raise DataChainError(f"Unknown command '{args.cmd}'.")
Expand Down Expand Up @@ -248,3 +251,18 @@ def upload_files(client: StudioClient, files: list[str]) -> list[str]:
if file_id:
file_ids.append(str(file_id))
return file_ids


def cancel_job(job_id: str, team_name: Optional[str]):
token = Config().read().get("studio", {}).get("token")
if not token:
raise DataChainError(
"Not logged in to Studio. Log in with 'datachain studio login'."
)

client = StudioClient(team=team_name)
response = client.cancel_job(job_id)
if not response.ok:
raise_remote_error(response.message)

Check warning on line 266 in src/datachain/studio.py

View check run for this annotation

Codecov / codecov/patch

src/datachain/studio.py#L266

Added line #L266 was not covered by tests

print(f"Job {job_id} canceled")
18 changes: 18 additions & 0 deletions tests/test_cli_studio.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,24 @@ def test_studio_rm_dataset(capsys, mocker):
}


def test_studio_cancel_job(capsys, mocker):
job_id = "8bddde6c-c3ca-41b0-9d87-ee945bfdce70"
with requests_mock.mock() as m:
m.post(f"{STUDIO_URL}/api/datachain/job/{job_id}/cancel", json={})

# Studio token is required
assert main(["studio", "cancel", job_id]) == 1
out = capsys.readouterr().err
assert "Not logged in to Studio" in out

# Set the studio token
with Config(ConfigLevel.GLOBAL).edit() as conf:
conf["studio"] = {"token": "isat_access_token", "team": "team_name"}

assert main(["studio", "cancel", job_id]) == 0
assert m.called


def test_studio_run(capsys, mocker, tmp_dir):
with Config(ConfigLevel.GLOBAL).edit() as conf:
conf["studio"] = {"token": "isat_access_token", "team": "team_name"}
Expand Down

0 comments on commit 6fce628

Please sign in to comment.