web3.eth.Eth.wait_for_transaction_receipt 函数采用可选的timeout 参数。默认情况下,它将等待120 秒,然后引发web3.exceptions.TimeExhausted。您可以做的是反复等待一小段时间,捕获异常,并检查您是否还需要等待收据。如果您不太关心取消不是立即的,则很容易实现。这是一个概念验证:
import logging
import sys
import threading
import time
logger = logging.getLogger() # for a clearer output
RECEIPT_WAITING_TIME = 5 # seconds
class FakeWeb3ExceptionTimeExhausted(Exception): pass
def fake_wait_for_transaction_receipt(timeout=120):
logger.info("waiting ...") # but it will never come
lock = threading.Lock()
acquired = lock.acquire()
assert acquired
re_acquired = lock.acquire(blocking=True, timeout=timeout) # can re-acquire the lock (already acquired), so will block until timeout
if not re_acquired:
raise FakeWeb3ExceptionTimeExhausted()
THREAD1_SHOULD_STOP_WAITING = False
def thread_1_func():
while True:
try:
result = fake_wait_for_transaction_receipt(timeout=RECEIPT_WAITING_TIME)
except FakeWeb3ExceptionTimeExhausted:
logger.info("pause waiting")
global THREAD1_SHOULD_STOP_WAITING
if THREAD1_SHOULD_STOP_WAITING:
logger.info("stop waiting <--")
break
else:
logger.info("resume waiting")
else:
logger.info("finish waiting")
# do something with the result
return # don't sys.exit here
def thread_2_func():
time.sleep(15) # let some time pass
# then change your mind
logger.info("--> cancel waiting")
global THREAD1_SHOULD_STOP_WAITING
THREAD1_SHOULD_STOP_WAITING = True
return # explicit
def main():
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter("%(threadName)s %(asctime)s %(message)s"))
logger.addHandler(handler)
logger.setLevel(logging.INFO)
thread1 = threading.Thread(target=thread_1_func, args=())
thread1.start()
thread2 = threading.Thread(target=thread_2_func, args=())
thread2.start()
thread1.join()
thread2.join()
sys.exit(0) # exit here
main()
Thread-1 2022-02-04 12:09:46,813 waiting ...
Thread-1 2022-02-04 12:09:51,814 pause waiting
Thread-1 2022-02-04 12:09:51,814 resume waiting
Thread-1 2022-02-04 12:09:51,814 waiting ...
Thread-1 2022-02-04 12:09:56,814 pause waiting
Thread-1 2022-02-04 12:09:56,814 resume waiting
Thread-1 2022-02-04 12:09:56,814 waiting ...
Thread-1 2022-02-04 12:10:01,815 pause waiting
Thread-1 2022-02-04 12:10:01,815 resume waiting
Thread-1 2022-02-04 12:10:01,815 waiting ...
Thread-2 2022-02-04 12:10:01,828 --> cancel waiting
Thread-1 2022-02-04 12:10:06,815 pause waiting
Thread-1 2022-02-04 12:10:06,815 stop waiting <--
将在更糟糕的情况下考虑取消RECEIPT_WAITING_TIME 秒后。您可以根据需要降低此值,但由于循环有开销,可能不会太低(亚秒级)。
这相当于调用web3.eth.Eth.get_transaction_receipt 会抛出web3.exceptions.TransactionNotFound,然后检查global,然后重试。
class FakeWeb3ExceptionTransactionNotFound(Exception): pass
def fake_get_transaction_receipt():
logger.info("get ...")
time.sleep(0.2) # takes a bit of time
raise FakeWeb3ExceptionTransactionNotFound() # never found
def thread_1_func_v2():
while True:
try:
result = fake_get_transaction_receipt()
except FakeWeb3ExceptionTransactionNotFound:
logger.info("not found")
global THREAD1_SHOULD_STOP_WAITING
if THREAD1_SHOULD_STOP_WAITING:
logger.info("stop waiting <--")
break
else:
logger.info("resume waiting")
else:
logger.info("finish waiting")
# do something with the result
return # don't sys.exit here
def main2():
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter("%(threadName)s %(asctime)s %(message)s"))
logger.addHandler(handler)
logger.setLevel(logging.INFO)
thread1 = threading.Thread(target=thread_1_func_v2, args=())
thread1.start()
thread2 = threading.Thread(target=thread_2_func, args=())
thread2.start()
thread1.join()
thread2.join()
sys.exit(0) # exit here
main2()
Thread-1 2022-02-04 12:19:59,014 get ...
Thread-1 2022-02-04 12:19:59,214 not found
Thread-1 2022-02-04 12:19:59,214 resume waiting
Thread-1 2022-02-04 12:19:59,214 get ...
Thread-1 2022-02-04 12:19:59,415 not found
Thread-1 2022-02-04 12:19:59,415 resume waiting
Thread-1 2022-02-04 12:19:59,415 get ...
[...]
Thread-1 2022-02-04 12:20:13,461 get ...
Thread-1 2022-02-04 12:20:13,661 not found
Thread-1 2022-02-04 12:20:13,661 resume waiting
Thread-1 2022-02-04 12:20:13,661 get ...
Thread-1 2022-02-04 12:20:13,862 not found
Thread-1 2022-02-04 12:20:13,862 resume waiting
Thread-1 2022-02-04 12:20:13,862 get ...
Thread-2 2022-02-04 12:20:14,029 --> cancel waiting
Thread-1 2022-02-04 12:20:14,062 not found
Thread-1 2022-02-04 12:20:14,063 stop waiting <--