forked from goodboy/tractor
Relay `SIGUSR1` to subactors for `stackscope` tracing
Since obvi we don't want to just only see the trace in the root most of the time ;) Currently the sig keeps firing twice in the root though, and i'm not sure why yet..runtime_to_msgspec
parent
3869e91b19
commit
d4155396bf
|
@ -23,12 +23,31 @@ into each ``trio.Nursery`` except it links the lifetimes of memory space
|
||||||
disjoint, parallel executing tasks in separate actors.
|
disjoint, parallel executing tasks in separate actors.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
from __future__ import annotations
|
||||||
|
import multiprocessing as mp
|
||||||
from signal import (
|
from signal import (
|
||||||
signal,
|
signal,
|
||||||
SIGUSR1,
|
SIGUSR1,
|
||||||
)
|
)
|
||||||
|
import traceback
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import trio
|
import trio
|
||||||
|
from tractor import (
|
||||||
|
_state,
|
||||||
|
log as logmod,
|
||||||
|
)
|
||||||
|
|
||||||
|
log = logmod.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from tractor._spawn import ProcessType
|
||||||
|
from tractor import (
|
||||||
|
Actor,
|
||||||
|
ActorNursery,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@trio.lowlevel.disable_ki_protection
|
@trio.lowlevel.disable_ki_protection
|
||||||
def dump_task_tree() -> None:
|
def dump_task_tree() -> None:
|
||||||
|
@ -41,9 +60,15 @@ def dump_task_tree() -> None:
|
||||||
recurse_child_tasks=True
|
recurse_child_tasks=True
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
log = get_console_log('cancel')
|
log = get_console_log(
|
||||||
|
name=__name__,
|
||||||
|
level='cancel',
|
||||||
|
)
|
||||||
|
actor: Actor = _state.current_actor()
|
||||||
log.pdb(
|
log.pdb(
|
||||||
f'Dumping `stackscope` tree:\n\n'
|
f'Dumping `stackscope` tree for actor\n'
|
||||||
|
f'{actor.name}: {actor}\n'
|
||||||
|
f' |_{mp.current_process()}\n\n'
|
||||||
f'{tree_str}\n'
|
f'{tree_str}\n'
|
||||||
)
|
)
|
||||||
# import logging
|
# import logging
|
||||||
|
@ -56,8 +81,13 @@ def dump_task_tree() -> None:
|
||||||
# ).exception("Error printing task tree")
|
# ).exception("Error printing task tree")
|
||||||
|
|
||||||
|
|
||||||
def signal_handler(sig: int, frame: object) -> None:
|
def signal_handler(
|
||||||
import traceback
|
sig: int,
|
||||||
|
frame: object,
|
||||||
|
|
||||||
|
relay_to_subs: bool = True,
|
||||||
|
|
||||||
|
) -> None:
|
||||||
try:
|
try:
|
||||||
trio.lowlevel.current_trio_token(
|
trio.lowlevel.current_trio_token(
|
||||||
).run_sync_soon(dump_task_tree)
|
).run_sync_soon(dump_task_tree)
|
||||||
|
@ -65,6 +95,26 @@ def signal_handler(sig: int, frame: object) -> None:
|
||||||
# not in async context -- print a normal traceback
|
# not in async context -- print a normal traceback
|
||||||
traceback.print_stack()
|
traceback.print_stack()
|
||||||
|
|
||||||
|
if not relay_to_subs:
|
||||||
|
return
|
||||||
|
|
||||||
|
an: ActorNursery
|
||||||
|
for an in _state.current_actor()._actoruid2nursery.values():
|
||||||
|
|
||||||
|
subproc: ProcessType
|
||||||
|
subactor: Actor
|
||||||
|
for subactor, subproc, _ in an._children.values():
|
||||||
|
log.pdb(
|
||||||
|
f'Relaying `SIGUSR1`[{sig}] to sub-actor\n'
|
||||||
|
f'{subactor}\n'
|
||||||
|
f' |_{subproc}\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(subproc, trio.Process):
|
||||||
|
subproc.send_signal(sig)
|
||||||
|
|
||||||
|
elif isinstance(subproc, mp.Process):
|
||||||
|
subproc._send_signal(sig)
|
||||||
|
|
||||||
|
|
||||||
def enable_stack_on_sig(
|
def enable_stack_on_sig(
|
||||||
|
@ -82,3 +132,6 @@ def enable_stack_on_sig(
|
||||||
# NOTE: not the above can be triggered from
|
# NOTE: not the above can be triggered from
|
||||||
# a (xonsh) shell using:
|
# a (xonsh) shell using:
|
||||||
# kill -SIGUSR1 @$(pgrep -f '<cmd>')
|
# kill -SIGUSR1 @$(pgrep -f '<cmd>')
|
||||||
|
#
|
||||||
|
# for example if you were looking to trace a `pytest` run
|
||||||
|
# kill -SIGUSR1 @$(pgrep -f 'pytest')
|
||||||
|
|
Loading…
Reference in New Issue