Skip to content

Commit

Permalink
Enhancing error messages (#1662)
Browse files Browse the repository at this point in the history
* enhancing error messages

* small tweak

* fixing the tests

* updated tests

* updated tests

* added another test

---------

Co-authored-by: Sankalp Sanand <sankalp@agnostiq.ai>
Co-authored-by: kessler-frost <ssanand@hawk.iit.edu>
  • Loading branch information
3 people authored May 25, 2023
1 parent 1653d5d commit 90d1560
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 20 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [UNRELEASED]

### Changed

- Error messages are propagated to stdout when the server is not started. These changes are applied to `dispatch`, `redispatch`, and `get_result`.

### Docs

- Fix typo in GCP Batch executor RTD.
Expand Down
25 changes: 18 additions & 7 deletions covalent/_dispatcher_plugins/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,17 @@ def wrapper(*args, **kwargs) -> str:
lattice_dispatch_id = None
try:
r = requests.post(
submit_dispatch_url, data=json_lattice, params={"disable_run": disable_run}
submit_dispatch_url,
data=json_lattice,
params={"disable_run": disable_run},
timeout=5,
)
r.raise_for_status()
lattice_dispatch_id = r.content.decode("utf-8").strip().replace('"', "")
except requests.exceptions.ConnectionError as e:
message = f"The Covalent dispatcher server is not running at {dispatcher_addr}. You must start Covalent (with `covalent start`) before dispatching your workflow."
app_log.error(message)
raise ConnectionError(message) from e
except requests.exceptions.ConnectionError:
message = f"The Covalent server cannot be reached at {dispatcher_addr}. Local servers can be started using `covalent start` in the terminal. If you are using a remote Covalent server, contact your systems administrator to report an outage."
print(message)
return

if not disable_run or triggers_data is None:
return lattice_dispatch_id
Expand Down Expand Up @@ -264,8 +267,16 @@ def func(*new_args, **new_kwargs):
dispatch_id, new_args, new_kwargs, replace_electrons, reuse_previous_results
)
redispatch_url = f"{dispatcher_addr}/api/redispatch"
r = requests.post(redispatch_url, json=body, params={"is_pending": is_pending})
r.raise_for_status()
try:
r = requests.post(
redispatch_url, json=body, params={"is_pending": is_pending}, timeout=5
)
r.raise_for_status()
except requests.exceptions.ConnectionError:
message = f"The Covalent server cannot be reached at {dispatcher_addr}. Local servers can be started using `covalent start` in the terminal. If you are using a remote Covalent server, contact your systems administrator to report an outage."
print(message)
return

return r.content.decode("utf-8").strip().replace('"', "")

return func
Expand Down
18 changes: 14 additions & 4 deletions covalent/_results_manager/results_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ def get_result(

raise ex

except requests.exceptions.ConnectionError:
return None

return result


Expand Down Expand Up @@ -111,10 +114,17 @@ def _get_result_from_dispatcher(
http.mount("http://", adapter)

result_url = f"{dispatcher_addr}/api/result/{dispatch_id}"
response = http.get(
result_url,
params={"wait": bool(int(wait)), "status_only": status_only},
)

try:
response = http.get(
result_url,
params={"wait": bool(int(wait)), "status_only": status_only},
timeout=5,
)
except requests.exceptions.ConnectionError:
message = f"The Covalent server cannot be reached at {dispatcher_addr}. Local servers can be started using `covalent start` in the terminal. If you are using a remote Covalent server, contact your systems administrator to report an outage."
print(message)
raise

if response.status_code == 404:
raise MissingLatticeRecordError
Expand Down
32 changes: 25 additions & 7 deletions tests/covalent_tests/dispatcher_plugins/local_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_get_redispatch_request_body_args_kwargs(mocker):

@pytest.mark.parametrize("is_pending", [True, False])
@pytest.mark.parametrize(
"replace_electrons,expected_arg",
"replace_electrons, expected_arg",
[(None, {}), ({"mock-electron-1": "mock-electron-2"}, {"mock-electron-1": "mock-electron-2"})],
)
def test_redispatch(mocker, replace_electrons, expected_arg, is_pending):
Expand All @@ -98,13 +98,29 @@ def test_redispatch(mocker, replace_electrons, expected_arg, is_pending):
"http://mock-config:mock-config/api/redispatch",
json={"mock-request-body"},
params={"is_pending": is_pending},
timeout=5,
)
requests_mock.post().raise_for_status.assert_called_once()
requests_mock.post().content.decode().strip().replace.assert_called_once_with('"', "")

get_request_body_mock.assert_called_once_with("mock-dispatch-id", (), {}, expected_arg, False)


def test_redispatch_unreachable(mocker):
"""Test the local re-dispatch function when the server is unreachable."""

mock_dispatch_id = "mock-dispatch-id"
dummy_dispatcher_addr = "http://localhost:12345"

message = f"The Covalent server cannot be reached at {dummy_dispatcher_addr}. Local servers can be started using `covalent start` in the terminal. If you are using a remote Covalent server, contact your systems administrator to report an outage."

mock_print = mocker.patch("covalent._dispatcher_plugins.local.print")

LocalDispatcher.redispatch(mock_dispatch_id, dispatcher_addr=dummy_dispatcher_addr)()

mock_print.assert_called_once_with(message)


def test_dispatching_a_non_lattice():
"""test dispatching a non-lattice"""

Expand All @@ -123,13 +139,15 @@ def workflow(a, b):
LocalDispatcher.dispatch(workflow)(1, 2)


def test_dispatch_when_no_server_is_running():
def test_dispatch_when_no_server_is_running(mocker):
"""test dispatching a lattice when no server is running"""

# the test suite is using another port, thus, with the dummy address below
# the covalent server is not running in some sense.
dummy_dispatcher_addr = "http://localhost:12345"

message = f"The Covalent server cannot be reached at {dummy_dispatcher_addr}. Local servers can be started using `covalent start` in the terminal. If you are using a remote Covalent server, contact your systems administrator to report an outage."

@ct.electron
def task(a, b, c):
return a + b + c
Expand All @@ -138,11 +156,11 @@ def task(a, b, c):
def workflow(a, b):
return task(a, b, c=4)

with pytest.raises(
ConnectionError,
match=f"The Covalent dispatcher server is not running at {dummy_dispatcher_addr}.",
):
LocalDispatcher.dispatch(workflow, dispatcher_addr=dummy_dispatcher_addr)(1, 2)
mock_print = mocker.patch("covalent._dispatcher_plugins.local.print")

LocalDispatcher.dispatch(workflow, dispatcher_addr=dummy_dispatcher_addr)(1, 2)

mock_print.assert_called_once_with(message)


def test_dispatcher_submit_api(mocker):
Expand Down
51 changes: 49 additions & 2 deletions tests/covalent_tests/results_manager_tests/results_manager_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,30 @@
from unittest.mock import ANY, MagicMock, Mock, call

import pytest
import requests

from covalent._results_manager import wait
from covalent._results_manager.results_manager import _get_result_from_dispatcher, cancel
from covalent._results_manager.results_manager import (
_get_result_from_dispatcher,
cancel,
get_result,
)
from covalent._shared_files.config import get_config

DISPATCH_ID = "91c3ee18-5f2d-44ee-ac2a-39b79cf56646"

def test_get_result_unreachable_dispatcher(mocker):
"""
Test that get_result returns None when
the dispatcher server is unreachable.
"""
mock_dispatch_id = "mock_dispatch_id"

mocker.patch(
"covalent._results_manager.results_manager._get_result_from_dispatcher",
side_effect=requests.exceptions.ConnectionError,
)

assert get_result(mock_dispatch_id) is None


@pytest.mark.parametrize(
Expand Down Expand Up @@ -67,6 +85,35 @@ def test_get_result_from_dispatcher(mocker, dispatcher_addr):
)


def test_get_result_from_dispatcher_unreachable(mocker):
"""
Test that _get_result_from_dispatcher raises an exception when
the dispatcher server is unreachable.
"""

# TODO: Will need to edit this once `_get_result_from_dispatcher` is fixed
# to actually throw an exception when the dispatcher server is unreachable
# instead of just hanging.

mock_dispatcher_addr = "mock_dispatcher_addr"
mock_dispatch_id = "mock_dispatch_id"

message = f"The Covalent server cannot be reached at {mock_dispatcher_addr}. Local servers can be started using `covalent start` in the terminal. If you are using a remote Covalent server, contact your systems administrator to report an outage."

mocker.patch("covalent._results_manager.results_manager.HTTPAdapter")
mock_session = mocker.patch("covalent._results_manager.results_manager.requests.Session")
mock_session.return_value.get.side_effect = requests.exceptions.ConnectionError

mock_print = mocker.patch("covalent._results_manager.results_manager.print")

with pytest.raises(requests.exceptions.ConnectionError):
_get_result_from_dispatcher(
mock_dispatch_id, wait=wait.LONG, dispatcher_addr=mock_dispatcher_addr
)

mock_print.assert_called_once_with(message)


def test_cancel_with_single_task_id(mocker):
mock_get_config = mocker.patch("covalent._results_manager.results_manager.get_config")
mock_request_post = mocker.patch(
Expand Down

0 comments on commit 90d1560

Please sign in to comment.