Skip to content

Instantly share code, notes, and snippets.

@carlos-jenkins
Last active June 15, 2020 17:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carlos-jenkins/886351907cc8a758de28630b7056520c to your computer and use it in GitHub Desktop.
Save carlos-jenkins/886351907cc8a758de28630b7056520c to your computer and use it in GitHub Desktop.
Just a generic polling function
from time import time
from asyncio import sleep
from .poll import NotReadyYet
async def poll(
func,
timeout_s=30.0, polling_s=5.0,
catchexcs=(NotReadyYet, ), pollcb=None,
):
"""
Poll until the polling function ``func`` returns.
:param function func: The polling function to call.
The function is called without arguments.
In case argument passing is required use a partial::
from functools import partial
result = poll(partial(myfunc, myarg1, myarg2))
:param float timeout_s: Maximum timeout, in seconds, for execution of the
polling.
:param float polling_s: Time in seconds to wait between calls to the
polling function.
:param tuple catchexcs: Collection of typed exceptions to catch to continue
polling. Any exception raised by the polling function that isn't included
in this tuple will be raised. By default, ``(Exception, )`` is used, which
will catch all exceptions except system exceptions.
:param function pollcb: Callback to call after each poll. Callback must
have a signature of::
def mycallback(retrynum, exc):
return True
With:
:param int retrynum: Times the polling function has been called.
:param Exception exc: Exception raised by the polling function ``func``.
:return: ``True`` continue polling, ``False`` to stop right away.
:rtype: bool
:return: The return value of polling function ``func``, or ``None`` if the
polling callback ``pollcb`` returns ``False``.
:rtype: Same as ``func`` return.
:raises TimeoutError: if timeout is reached.
"""
end = time() + timeout_s
retrynum = 0
exc = None
while True:
retrynum += 1
try:
return await func()
except catchexcs as e:
exc = e
if pollcb is not None and not await pollcb(retrynum, exc):
return None
if end - time() >= polling_s:
await sleep(polling_s)
continue
raise TimeoutError(
'Timeout waiting for {}'.format(getattr(func, '__name__', str(func)))
)
__all__ = [
'NotReadyYet',
'poll',
]
from time import time, sleep
class NotReadyYet(Exception):
"""
Typed exception that functions to be polled can raise to continue polling.
"""
def poll(
func,
timeout_s=30.0, polling_s=5.0,
catchexcs=(NotReadyYet, ), pollcb=None,
):
"""
Poll until the function to be polled returns.
:param function func: The function to be polled.
The function is called without arguments.
In case argument passing is required use a partial::
from functools import partial
result = poll(partial(myfunc, myarg1, myarg2))
:param float timeout_s: Timeout, in seconds, for execution of the polling.
This is an approximate, real execution is between::
timeout_s - polling_s <= execution <= timeout_s + time(func) + time(pollcb)
:param float polling_s: Time in seconds to wait between calls to the
polling function.
:param tuple catchexcs: Collection of typed exceptions to catch to continue
polling. Any exception raised by the polling function that isn't included
in this tuple will be raised. By default, ``(NotReadyYet, )`` is used so
the function to be polled will need to raise this exception to continue
execution. Alternatively, ``(Exception, )`` may be used to catch all
exceptions except interpreter exceptions.
:param function pollcb: Callback to call after each poll. Callback must
have a signature of::
def mycallback(retrynum, exc):
return True
With:
:param int retrynum: Times the polling function has been called.
:param Exception exc: Exception raised by the polling function ``func``.
:return: ``True`` continue polling, ``False`` to stop right away.
:rtype: bool
:return: The return value of polling function ``func``, or ``None`` if the
polling callback ``pollcb`` returns ``False``.
:rtype: Same as ``func`` return.
:raises TimeoutError: if timeout is reached.
""" # noqa
end = time() + timeout_s
retrynum = 0
exc = None
while True:
retrynum += 1
try:
return func()
except catchexcs as e:
exc = e
if pollcb is not None and not pollcb(retrynum, exc):
return None
if end - time() >= polling_s:
sleep(polling_s)
continue
raise TimeoutError(
'Timeout waiting for {}'.format(getattr(func, '__name__', str(func)))
)
__all__ = [
'NotReadyYet',
'poll',
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment