Skip to content

Commit 5cae434

Browse files
author
Andrei Neagu
committed
refactored
1 parent d227217 commit 5cae434

File tree

5 files changed

+62
-27
lines changed

5 files changed

+62
-27
lines changed

packages/service-library/src/servicelib/long_running_interfaces/_client.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010

1111
from ._errors import (
1212
AlreadyStartedError,
13-
NoMoreRetryAttemptsError,
13+
FinishedWithError,
1414
TimedOutError,
15+
UnexpectedNoMoreRetryAttemptsError,
1516
UnexpectedResultTypeError,
1617
UnexpectedStatusError,
1718
)
@@ -128,8 +129,26 @@ async def _decrease_remaining_attempts_or_raise(
128129
remaining_attempts = await self._format_remaining_attempts(
129130
unique_id, retry_count
130131
)
131-
raise NoMoreRetryAttemptsError(
132+
# report remote error if there is one
133+
if last_result and last_result.error is not None:
134+
_logger.warning(
135+
"unique_id='%s', finished with error from remote: %s='%s'\n%s",
136+
unique_id,
137+
last_result.error.error_type,
138+
last_result.error.error_message,
139+
last_result.error.traceback,
140+
)
141+
raise FinishedWithError(
142+
unique_id=unique_id,
143+
error=last_result.error.error_type,
144+
message=last_result.error.error_message,
145+
traceback=last_result.error.traceback,
146+
)
147+
148+
# NOTE: this edge case should not happen
149+
raise UnexpectedNoMoreRetryAttemptsError(
132150
unique_id=unique_id,
151+
retry_count=retry_count,
133152
remaining_attempts=remaining_attempts,
134153
last_result=last_result,
135154
)

packages/service-library/src/servicelib/long_running_interfaces/_errors.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ class UnexpectedJobNotFoundError(BaseLongRunningError):
1111
)
1212

1313

14-
class NoMoreRetryAttemptsError(BaseLongRunningError):
15-
msg_template = "attempt {remaining_attempts} for unique_id='{unique_id}' with last_result='{last_result}'"
14+
class FinishedWithError(BaseLongRunningError):
15+
msg_template = "unique_id='{unique_id}' finished with error='{error}' message='{message}'\n{traceback}"
16+
17+
18+
class UnexpectedNoMoreRetryAttemptsError(FinishedWithError):
19+
msg_template = "attempt {remaining_attempts} of {retry_count} for unique_id='{unique_id}' with last_result='{last_result}'"
1620

1721

1822
class UnexpectedStatusError(BaseLongRunningError):

packages/service-library/src/servicelib/long_running_interfaces/_models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def unique_id(self) -> JobUniqueId:
3838

3939

4040
class ErrorModel(BaseModel):
41+
error_type: type
4142
error_message: str
4243
traceback: str
4344

packages/service-library/src/servicelib/long_running_interfaces/_rpc/server.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,9 @@ async def result(self, unique_id: JobUniqueId) -> ResultModel:
125125
except Exception as e: # pylint:disable=broad-exception-caught
126126
formatted_traceback = "\n".join(traceback.format_tb(e.__traceback__))
127127
return ResultModel(
128-
error=ErrorModel(error_message=f"{e}", traceback=formatted_traceback)
128+
error=ErrorModel(
129+
error_type=type(e),
130+
error_message=f"{e}",
131+
traceback=formatted_traceback,
132+
)
129133
)

packages/service-library/tests/long_running_interfaces/test_workflow.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@
88
from typing import Any
99

1010
import pytest
11-
from pydantic import NonNegativeInt
11+
from pydantic import NonNegativeInt, ValidationError
1212
from servicelib.long_running_interfaces import Client, LongRunningNamespace, Server
13-
from servicelib.long_running_interfaces._errors import (
14-
NoMoreRetryAttemptsError,
15-
TimedOutError,
16-
)
13+
from servicelib.long_running_interfaces._errors import FinishedWithError, TimedOutError
1714
from servicelib.long_running_interfaces_runners.asyncio_tasks import (
1815
AsyncioTasksJobInterface,
1916
AsyncTaskRegistry,
@@ -80,16 +77,6 @@ async def sleep_forever_f() -> None:
8077
await server.teardown()
8178

8279

83-
# Figure out how to cause interruption in SERVER & CLIENT code, in order to simulate shakyness in the tests
84-
# write something that cancels and restarts the job runtime
85-
86-
# TODO: add the following tests
87-
# start a job and wait for it to finish
88-
# start a job that takes too much time
89-
# start a job that raises an error
90-
# start a job that after 95% of timeout raises an errors x times in a row (we can test if it can successfully finish)
91-
92-
9380
@dataclass
9481
class _CustomClass:
9582
number: float
@@ -123,11 +110,6 @@ async def test_workflow(
123110
assert type(result) is expected_type
124111

125112

126-
# TODO: count error in logs to be sure soemthing is worng
127-
# TODO: count that it's missing with retry_count=0 and that it raises a vlidation error
128-
# TODO: figure out a way to raise the error
129-
130-
131113
async def test_timeout_error(server: Server, client: Client):
132114
with pytest.raises(TimedOutError):
133115
await client.ensure_result(
@@ -147,13 +129,38 @@ async def test_timeout_during_failing_retry(server: Server, client: Client):
147129

148130

149131
@pytest.mark.parametrize("retry_count", [1, 2])
150-
async def test_stops_after_n_retry_attempts(
132+
async def test_raisese_after_n_retry_attempts(
151133
server: Server, client: Client, retry_count: NonNegativeInt
152134
):
153-
with pytest.raises(NoMoreRetryAttemptsError):
135+
with pytest.raises(FinishedWithError):
154136
await client.ensure_result(
155137
"raising_f",
156138
expected_type=type(None),
157139
timeout=timedelta(seconds=10),
158140
retry_count=retry_count,
159141
)
142+
143+
144+
async def test_timeout_error_retry_count_zero(server: Server, client: Client):
145+
with pytest.raises(ValidationError) as exec_info:
146+
await client.ensure_result(
147+
"some_f",
148+
expected_type=type(None),
149+
timeout=timedelta(seconds=10),
150+
retry_count=0,
151+
)
152+
153+
assert "retry_count" in f"{exec_info.value}"
154+
assert "Input should be greater than 0" in f"{exec_info.value}"
155+
156+
157+
# Figure out how to cause interruption in SERVER & CLIENT code, in order to
158+
# simulate shakyness in the tests
159+
# write something that cancels and restarts the job runtime
160+
161+
# TODO: add the following tests
162+
# start a job and wait for it to finish
163+
# start a job that takes too much time
164+
# start a job that raises an error
165+
# start a job that after 95% of timeout raises an errors x times in a row
166+
# (we can test if it can successfully finish)

0 commit comments

Comments
 (0)