Skip to content
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

use new param to specify first wait period #192

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/user-guide/repeated-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Here is a more detailed description of the various keyword arguments for `repeat
* `seconds: float` : The number of seconds to wait between successive calls
* `wait_first: bool = False` : If `False` (the default), the wrapped function is called immediately when the decorated
function is first called. If `True`, the decorated function will wait one period before making the first call to the wrapped function
* `wait_first_seconds: float = 0` : If `wait_first` is `True`, `wait_first_seconds` specifies the duration of the first wait period for the wrapped function to be called. If left as default, it will use `seconds` as the duration.
* `logger: Optional[logging.Logger] = None` : If you pass a logger, any exceptions raised in the repeating execution loop will be logged (with a traceback)
to the provided logger.
* `raise_exceptions: bool = False`
Expand Down
8 changes: 7 additions & 1 deletion fastapi_utils/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def repeat_every(
*,
seconds: float,
wait_first: bool = False,
wait_first_seconds: float = 0.0,
logger: Optional[logging.Logger] = None,
raise_exceptions: bool = False,
max_repetitions: Optional[int] = None,
Expand All @@ -32,6 +33,8 @@ def repeat_every(
The number of seconds to wait between repeated calls
wait_first: bool (default False)
If True, the function will wait for a single period before the first call
wait_first_seconds: float (default 0.0)
If > 0 and wait_first = True, specifies a duration in seconds before the first call, other than `seconds`.
logger: Optional[logging.Logger] (default None)
The logger to use to log any exceptions raised by calls to the decorated function.
If not provided, exceptions will not be logged by this function (though they may be handled by the event loop).
Expand All @@ -57,7 +60,10 @@ async def wrapped() -> None:
async def loop() -> None:
nonlocal repetitions
if wait_first:
await asyncio.sleep(seconds)
if wait_first_seconds:
await asyncio.sleep(wait_first_seconds)
else:
await asyncio.sleep(seconds)
while max_repetitions is None or repetitions < max_repetitions:
try:
if is_coroutine:
Expand Down
13 changes: 13 additions & 0 deletions tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ def repeatedly_print_hello() -> None:
assert err == ""


@pytest.mark.asyncio
async def test_repeat_print_wait_first_seconds(capsys: CaptureFixture) -> None:
@repeat_every(seconds=0.07, max_repetitions=3, wait_first=True, wait_first_seconds=0.1)
def repeatedly_print_hello() -> None:
print("hello")

await repeatedly_print_hello()
await asyncio.sleep(0.18) #  wait for 0.07 + 0.1 secs
out, err = capsys.readouterr()
assert out == "hello\n" * 2, "Printed 'hello' twice"
assert err == ""


@pytest.mark.asyncio
async def test_repeat_unlogged_error(caplog: LogCaptureFixture) -> None:
@repeat_every(seconds=0.07, max_repetitions=None)
Expand Down