-
Notifications
You must be signed in to change notification settings - Fork 172
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
Fix: tasks.repeat_every() and related tests #310
Conversation
Fix/tasks blocking
@yuval9313 I've checked the previous failed builds and found they were complaining about function complexity and unsorted imports. I've all fixed and tested builds in my local machine so should be all good now. One problem is that: the remaining two failing tests ( |
@mgkid3310 I want to check the issue you are facing myself, to do so you must first finish all the test suites EDIT: Since it wasn't issue beforehand I'd accept this PR as is (with the test deleted) but I also want an issue about this since it means that exceptions inside repeat every simply won't be raised properly in-app and the app would attempt to continue either way |
@yuval9313 I've manually tested the code via: @asynccontextmanager
async def lifespan(_):
await test()
yield
@repeat_every(seconds=5, raise_exceptions=True)
async def test():
print('Hello World!')
raise ValueError('Test error')
app = FastAPI(lifespan=lifespan)
@app.get('/', include_in_schema=False)
async def root():
return Response(status_code=status.HTTP_200_OK)
def main():
uvicorn.run(f'main:app', host='0.0.0.0', port=8000, log_level='info', reload=True)
if __name__ == '__main__':
main()
Sure since the repeat_every() works on background the application works find regardless of the exception from the test func, the repeat does not continue. The problem is that: 1) the test concludes itself with fail before the repeat_every() throws an exception; or 2) the exception is not compatible with the pytest environment? not in the same thread? kind of problem. EDIT: |
@mgkid3310, and now it seems like we found the reason why repeat_every is blocking currently, I'm OK with merging this, but just like your snippet, the app started regardless the exception |
@yuval9313 typing changed to using I think we're at the point where we need to think what we want from
|
@mgkid3310 I understand, but I think it is important for every dev to handle any error might occur in the task himself, I don't mind the application crashing after a while if I put I've noticed we can check the futures |
@yuval9313 The problem is that for the host code to handle the exception in any way, the host app (FastAPI) won't start at all. Moreover, since the host code doesn't know when the exception may occur, it is quite hard to implement an event or such. From the link you provided, it seems like the future object from ensure_future() can have exceptions set inside the loop and be checked for exceptions later. It might be worth a try. Sure, this still won't do anything on its own, but at least it will provide a way for users to use the future object to make an event listener or so. |
After consulting with some colleagues I've decided that the In version V1.0 we will remove if raise_exception is callback, add the callback to the future if raise_exception is True, log the exception if logger used and then add a warning that tells devs to migrate to Also, dispose of the tests that makes issues, I'll add them later |
I'm not sure if Anyways, to summarize before actually coding:
|
|
@yuval9313 If
then check for stop_flag in while statement. This way we can offer the user a way to gently continue or terminate the loop without raising exception uncatched (printing the exception in raw format on console). |
I don't like it that way, it is too much of a side effect, also I don't expect devs to be cautious about the return status of their exception handlers |
@yuval9313 Understood, I'm working on the code and I'll push once the code is done. |
…ise_exception added
With the last commit both the logger (as on_exception is upward compatible with logger by having a logger inside on_exception) and raise_exceptions raises deprecation warning via the warning module ( |
Found that both tests for sync and async functions were running only with sync functions, so fixed that problem so that TestRepeatEveryWithAsynchronousFunction actually runs tests for async functions (all for func, on_complete and on_exception) |
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 run poetry add --dev pytest-timeout
it seems like pytest.mark.timeout
is missing when running tests locally and I see no changes in poetry lock
Although the package lock is updated, the core problem seemed to be with type hint with async functions. However when I moved over to devcontainer with python3.9, the type error does not show and the timeout package error is ignored (it was not an error which breaks the build process but just a warning). The poetry lock is fixed along with typo though. |
Turns out that the mypy didn't like conditional types such as: func = self.increase_counter_async if is_async else self.increase_counter
return decorator(func) where the func can be |
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [fastapi-utils](https://fastapi-utils.davidmontague.xyz) ([source](https://togithub.com/dmontagu/fastapi-utils)) | `^0.6.0` -> `^0.7.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/fastapi-utils/0.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/fastapi-utils/0.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/fastapi-utils/0.6.0/0.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/fastapi-utils/0.6.0/0.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>dmontagu/fastapi-utils (fastapi-utils)</summary> ### [`v0.7.0`](https://togithub.com/dmontagu/fastapi-utils/releases/tag/0.7.0) [Compare Source](https://togithub.com/dmontagu/fastapi-utils/compare/v0.6.0...0.7.0) #### What's Changed - Attempt to fix docs by [@​yuval9313](https://togithub.com/yuval9313) in [https://github.com/dmontagu/fastapi-utils/pull/303](https://togithub.com/dmontagu/fastapi-utils/pull/303) - Update README.md by [@​yooyea](https://togithub.com/yooyea) in [https://github.com/dmontagu/fastapi-utils/pull/304](https://togithub.com/dmontagu/fastapi-utils/pull/304) - Fix typo by [@​yuval9313](https://togithub.com/yuval9313) in [https://github.com/dmontagu/fastapi-utils/pull/312](https://togithub.com/dmontagu/fastapi-utils/pull/312) - Fix: tasks.repeat_every() and related tests by [@​mgkid3310](https://togithub.com/mgkid3310) in [https://github.com/dmontagu/fastapi-utils/pull/310](https://togithub.com/dmontagu/fastapi-utils/pull/310) - Create new release by [@​yuval9313](https://togithub.com/yuval9313) in [https://github.com/dmontagu/fastapi-utils/pull/314](https://togithub.com/dmontagu/fastapi-utils/pull/314) #### New Contributors - [@​yooyea](https://togithub.com/yooyea) made their first contribution in [https://github.com/dmontagu/fastapi-utils/pull/304](https://togithub.com/dmontagu/fastapi-utils/pull/304) - [@​mgkid3310](https://togithub.com/mgkid3310) made their first contribution in [https://github.com/dmontagu/fastapi-utils/pull/310](https://togithub.com/dmontagu/fastapi-utils/pull/310) **Full Changelog**: fastapiutils/fastapi-utils@v0.6.0...0.7.0 </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/ddoroshev/pylerplate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4zOTMuMCIsInVwZGF0ZWRJblZlciI6IjM3LjM5My4wIiwidGFyZ2V0QnJhbmNoIjoiZmFzdGFwaSIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Original Issue: #305 & #307
Original PR: #308
Purpose of PR
Since 0.6.0 any use of
tasks.repeat_every()
in apllication startup have halted further app processes. The cause was found to be the use ofawait
keyword forloop()
but further testing by @Keiishu have shown that the tests fortasks.repeat_every()
does not allow the use ofasyncio.ensure_future()
, but rather results in failed tests.This PR intends to both: 1) fix the
tasks.repeat_every()
; and 2) fix the related tests.Chnages to codes
repeat_every()
on_complete
with typeNoArgsNoReturnFuncT
(but compatible with async func) was added. Initial purpose was to allow tests to add a way to add event to catch when the loop has ended, but I guess this parameter can be used for other purposes in production.repetitions = 0
have been moved so thatnonlocal
keyword is not needed and some linebreaks were added for better readability.tests/tests_tasks.py
completed
state andloop_completed()
fucntion were added to test base class. This allows test cases to wait for the loop to complete by usingawait self.completed.wait()
statement. Timeout was added to prevent function hangs, but it requirespytest-timeout
package from pip to work and without it the timeout decorator will have no effect.raising_task
andsuppressed_exception_task
are no longer staticmethod as they needself.loop_completed
as parameters.TestRepeatEveryWithSynchronousFunction
andTestRepeatEveryWithAsynchronousFunction
such asincrease_counter_task
have been moved toTestRepeatEveryBase
.TODO
test_raise_exceptions_true
test cases still result fail, so it needs to be fixed.test_raise_exceptions_false
do result pass, but I doubt if that's valid.