util: add AsyncHangDetector, and use it for lnpeer._process_message
This commit is contained in:
@@ -22,7 +22,7 @@ from . import ecc
|
||||
from .ecc import ecdsa_sig64_from_r_and_s, ecdsa_der_sig_from_ecdsa_sig64, ECPubkey
|
||||
from . import constants
|
||||
from .util import (bfh, log_exceptions, ignore_exceptions, chunks, OldTaskGroup,
|
||||
UnrelatedTransactionException, error_text_bytes_to_safe_str)
|
||||
UnrelatedTransactionException, error_text_bytes_to_safe_str, AsyncHangDetector)
|
||||
from . import transaction
|
||||
from .bitcoin import make_op_return, DummyAddress
|
||||
from .transaction import PartialTxOutput, match_script_against_template, Sighash
|
||||
@@ -240,7 +240,11 @@ class Peer(Logger):
|
||||
# note: the message handler might be async or non-async. In either case, by default,
|
||||
# we wait for it to complete before we return, i.e. before the next message is processed.
|
||||
if asyncio.iscoroutinefunction(f):
|
||||
await f(*args)
|
||||
async with AsyncHangDetector(
|
||||
message=f"message handler still running for {message_type.upper()}",
|
||||
logger=self.logger,
|
||||
):
|
||||
await f(*args)
|
||||
else:
|
||||
f(*args)
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
# SOFTWARE.
|
||||
import binascii
|
||||
import concurrent.futures
|
||||
import logging
|
||||
import os, sys, re, json
|
||||
from collections import defaultdict, OrderedDict
|
||||
from typing import (NamedTuple, Union, TYPE_CHECKING, Tuple, Optional, Callable, Any,
|
||||
@@ -488,6 +489,35 @@ def profiler(func=None, *, min_threshold: Union[int, float, None] = None):
|
||||
return do_profile
|
||||
|
||||
|
||||
class AsyncHangDetector:
|
||||
"""Context manager that logs every `n` seconds if encapsulated context still has not exited."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
period_sec: int = 15,
|
||||
message: str,
|
||||
logger: logging.Logger = None,
|
||||
):
|
||||
self.period_sec = period_sec
|
||||
self.message = message
|
||||
self.logger = logger or _logger
|
||||
|
||||
async def _monitor(self):
|
||||
# note: this assumes that the event loop itself is not blocked
|
||||
t0 = time.monotonic()
|
||||
while True:
|
||||
await asyncio.sleep(self.period_sec)
|
||||
t1 = time.monotonic()
|
||||
self.logger.info(f"{self.message} (after {t1 - t0:.2f} sec)")
|
||||
|
||||
async def __aenter__(self):
|
||||
self.mtask = asyncio.create_task(self._monitor())
|
||||
|
||||
async def __aexit__(self, exc_type, exc, tb):
|
||||
self.mtask.cancel()
|
||||
|
||||
|
||||
def android_ext_dir():
|
||||
from android.storage import primary_external_storage_path
|
||||
return primary_external_storage_path()
|
||||
|
||||
Reference in New Issue
Block a user