-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Job Cancelation #998
Job Cancelation #998
Conversation
Args: | ||
job_ids: The UUID of the job (returned when the job was created). | ||
kwargs: Extra options needed to fetch jobs. | ||
- cq_token: CQ Cloud credentials. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't necessary (we recommend passing credentials when instantiating the client instead of for each call)
- cq_token: CQ Cloud credentials. |
"""Cancel jobs associated with given job ids. | ||
|
||
Args: | ||
job_ids: The UUID of the job (returned when the job was created). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
job_ids: The UUID of the job (returned when the job was created). | |
job_ids: The UUIDs of the jobs (returned when the jobs were created). |
@@ -192,6 +192,34 @@ def get_job(self, job_id: str) -> dict[str, str]: | |||
""" | |||
return self.fetch_jobs([job_id])[job_id] | |||
|
|||
def cancel_jobs( | |||
self, | |||
job_ids: list[str], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
job_ids: list[str], | |
job_ids: Sequence[str], |
vendor throws error when trying to cancel. | ||
""" | ||
job_ids = self._job_id.split(",") | ||
self._backend._provider._client.cancel_jobs(job_ids, kwargs=kwargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self._backend._provider._client.cancel_jobs(job_ids, kwargs=kwargs) | |
self._backend._provider._client.cancel_jobs(job_ids, **kwargs) |
cirq-superstaq/cirq_superstaq/job.py
Outdated
SuperstaqServerException: If unable to get the status of the job from the API. | ||
""" | ||
job_ids = self._job_id.split(",") | ||
self._client.cancel_jobs(job_ids, kwargs=kwargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self._client.cancel_jobs(job_ids, kwargs=kwargs) | |
self._client.cancel_jobs(job_ids, **kwargs) |
def cancel_jobs( | ||
self, | ||
job_ids: list[str], | ||
**kwargs: Any, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this pass?
**kwargs: Any, | |
**kwargs: object, |
(and ditto anywhere else we're adding Any
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes.
response_content = self._handle_response(response) | ||
if response.ok: | ||
return response | ||
return response_content |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for noticing/fixing this! one thought: we probably only want to print warnings in the event of non-retriable status codes. what if we just replaced these lines in _handle_status_codes
:
client-superstaq/general-superstaq/general_superstaq/superstaq_client.py
Lines 756 to 759 in 9c99804
try: | |
json_content = response.json() | |
except requests.JSONDecodeError: | |
json_content = None |
to
try:
json_content = self._handle_response(response)
except requests.JSONDecodeError:
json_content = None
(and then reverted the change to _handle_response
, which shouldn't be necessary anymore)
- cq_token: CQ Cloud credentials. | ||
|
||
Returns: | ||
A dictionary mapping the job id to the cancellation attempt result or an error message. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might need an update: by the time we get here i think all that's left in the dict is {"succeeded": [<ids>]}
(also might be reasonable to just return the list of ids, instead of the full dictionary)
@@ -797,13 +821,14 @@ def _make_request(self, request: Callable[[], requests.Response]) -> requests.Re | |||
TimeoutError: If the requests retried for more than `max_retry_seconds`. | |||
|
|||
Returns: | |||
The `request.Response` from the final successful request call. | |||
The 'requests.Response' from the final successful request call. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'requests.Response' from the final successful request call. | |
The `requests.Response` from the final successful request call. |
(backticks indicate inline code)
response1 = mock.MagicMock() | ||
response2 = mock.MagicMock() | ||
mock_post.side_effect = [response1, response2] | ||
response1.ok = False | ||
response1.status_code = requests.codes.service_unavailable | ||
response2.ok = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this can be streamlined a bit:
response1 = mock.MagicMock() | |
response2 = mock.MagicMock() | |
mock_post.side_effect = [response1, response2] | |
response1.ok = False | |
response1.status_code = requests.codes.service_unavailable | |
response2.ok = True | |
response1 = mock.MagicMock(ok=False, status_code=requests.codes.service_unavailable) | |
response2 = mock.MagicMock(ok=True) | |
mock_post.side_effect = [response1, response2] |
with mock.patch( | ||
"general_superstaq.superstaq_client._SuperstaqClient.cancel_jobs", return_value=None | ||
) as mock_cancel: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this work?
with mock.patch( | |
"general_superstaq.superstaq_client._SuperstaqClient.cancel_jobs", return_value=None | |
) as mock_cancel: | |
with mock.patch("requests.post", return_value=requests.MagicMock(ok=True)) as mock_post: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original test passes so the mock seems to be called twice. The suggestion passes too with a minor fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great, can we make the same change in qss then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please explain why the new mock is better? Is the previous one stopping the program calls too early by returning None
at _client.cancel_jobs()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the previous one stopping the program calls too early by returning
None
at_client.cancel_jobs()
?
exactly - in general we want to be mocking as little as possible. basically all job.cancel()
does is call client.cancel_jobs
- if we mock that all we're really testing is the mock itself, not the actual interface between the two methods
in this case the logic is simple enough that it probably doesn't matter. But say we updated _client.cancel_jobs
to take a different kind of input, but forgot to update job.cancel()
- the previous test wouldn't catch this because we were replacing its call to _client.cancel_jobs()
with a mocked function that accepts any input (note in this example the error would hopefully be caught by mypy, but that's not always the case)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Thank you!
cirq-superstaq/cirq_superstaq/job.py
Outdated
@@ -151,6 +151,16 @@ def status(self) -> str: | |||
self._update_status_queue_info() | |||
return self._overall_status | |||
|
|||
def cancel(self, **kwargs: Any) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def cancel(self, **kwargs: Any) -> None: | |
def cancel(self, **kwargs: object) -> None: |
@@ -177,6 +177,16 @@ def _check_if_stopped(self) -> None: | |||
self._job_id, self._overall_status | |||
) | |||
|
|||
def cancel(self, **kwargs: Any) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def cancel(self, **kwargs: Any) -> None: | |
def cancel(self, **kwargs: object) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lg % a few nits
cirq-superstaq/cirq_superstaq/job.py
Outdated
"""Cancel the current job if it is not in a terminal state. | ||
|
||
Args: | ||
kwargs: Extra options needed to fetch jobs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kwargs: Extra options needed to fetch jobs. | |
kwargs: Extra options needed to fetch jobs. |
|
||
Args: | ||
job_ids: The UUIDs of the jobs (returned when the jobs were created). | ||
kwargs: Extra options needed to fetch jobs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kwargs: Extra options needed to fetch jobs. | |
kwargs: Extra options needed to fetch jobs. |
Raises: | ||
SuperstaqServerException: For other API call failures. | ||
""" | ||
json_dict: dict[str, Any] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
json_dict: dict[str, Any] = { | |
json_dict: dict[str, list[str]] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks a few things. Since job_ids
is a Sequence[str]
type, we have to cast it to a list. Also, json.dumps
returns a string so json_dict["options"]
will have type str
and not list[str]
. I don't think server is designed to handle json_dict["options"]
being a list
type either. Should I keep it at Any
or should I do some type casting to fix these issues?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah my bad. what about this?
json_dict: dict[str, Any] = { | |
json_dict: dict[str, str | Sequence[str]] = { |
"""Cancel the current job if it is not in a terminal state. | ||
|
||
Args: | ||
kwargs: Extra options needed to fetch jobs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kwargs: Extra options needed to fetch jobs. | |
kwargs: Extra options needed to fetch jobs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm!
Addressed #822.