Skip to content

Instantly share code, notes, and snippets.

@fabiocerqueira
Last active October 18, 2020 09:28
Show Gist options
  • Save fabiocerqueira/9fbeae90e41dc0cb73e46e44edede2c2 to your computer and use it in GitHub Desktop.
Save fabiocerqueira/9fbeae90e41dc0cb73e46e44edede2c2 to your computer and use it in GitHub Desktop.
from functools import wraps
from twisted.internet import defer, reactor
from twisted.python import failure
class DeferTimeoutError(Exception):
pass
def with_timeout(secs):
def inner(my_func):
@wraps(my_func)
def wrapper(*args, **kwargs):
def defer_cancel(d):
if not d.called:
d._suppressAlreadyCalled = True
d.errback(
failure.Failure(
DeferTimeoutError(
"{} timeout after {} secs".format(my_func.__name__, secs)
)
)
)
def completed(passthru):
if timeout_watcher.active():
timeout_watcher.cancel()
return passthru
d = my_func(*args, **kwargs)
d._canceller = defer_cancel
timeout_watcher = reactor.callLater(secs, d.cancel)
d.addBoth(completed)
return d
return wrapper
return inner
import time
import sys
from timeout_helper import DeferTimeoutError, with_timeout
from twisted.internet import defer, reactor
from twisted.web.client import Agent
# Example with_timeout usage
@defer.inlineCallbacks
def my_client_function(fake_delay):
agent = Agent(reactor, connectTimeout=5)
requester = with_timeout(secs=5)(agent.request)
response = yield requester(
"GET", "https://httpbin.org/delay/{}".format(fake_delay)
)
defer.returnValue(response.code)
@defer.inlineCallbacks
def main(delay):
start = time.time()
try:
result = yield my_client_function(delay)
print("status_code: {}".format(result))
except DeferTimeoutError:
print("timedout :(")
end = time.time()
print("Exec time: {}s".format(end - start))
reactor.stop()
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Example: python usage.py 10")
sys.exit(1)
delay = sys.argv[1]
reactor.callLater(0, main, delay)
reactor.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment