-
Notifications
You must be signed in to change notification settings - Fork 14
Ctx debugger #220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ctx debugger #220
Changes from 21 commits
969bce3
b369b91
6f05f5d
49d439b
63bdddd
23a1622
0f2a39a
37a1897
0fdcfa0
5b38948
ef89ed9
be1fcb2
551816e
44bfacc
09f00a5
632c666
13b76c9
b3d28a1
0afa7f0
6006adc
f173012
674fbbc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| ''' | ||
| fast fail test with a context. | ||
| ensure the partially initialized sub-actor process | ||
| doesn't cause a hang on error/cancel of the parent | ||
| nrusery. | ||
|
|
||
| ''' | ||
| import trio | ||
| import tractor | ||
|
|
||
|
|
||
| @tractor.context | ||
| async def sleep( | ||
| ctx: tractor.Context, | ||
| ): | ||
| await trio.sleep(0.5) | ||
| await ctx.started() | ||
| await trio.sleep_forever() | ||
|
|
||
|
|
||
| async def open_ctx( | ||
| n: tractor._trionics.ActorNursery | ||
| ): | ||
|
|
||
| # spawn both actors | ||
| portal = await n.start_actor( | ||
| name='sleeper', | ||
| enable_modules=[__name__], | ||
| ) | ||
|
|
||
| async with portal.open_context( | ||
| sleep, | ||
| ) as (ctx, first): | ||
| assert first is None | ||
|
|
||
|
|
||
| async def main(): | ||
|
|
||
| async with tractor.open_nursery( | ||
| debug_mode=True, | ||
| loglevel='runtime', | ||
| ) as an: | ||
|
|
||
| async with trio.open_nursery() as n: | ||
| n.start_soon(open_ctx, an) | ||
|
|
||
| await trio.sleep(0.2) | ||
| await trio.sleep(0.1) | ||
| assert 0 | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| trio.run(main) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
|
|
||
| import trio | ||
| import tractor | ||
|
|
||
|
|
||
| async def key_error(): | ||
| "Raise a ``NameError``" | ||
| return {}['doggy'] | ||
|
|
||
|
|
||
| async def main(): | ||
| """Root dies | ||
|
|
||
| """ | ||
| async with tractor.open_nursery( | ||
| debug_mode=True, | ||
| loglevel='debug' | ||
| ) as n: | ||
|
|
||
| # spawn both actors | ||
| portal = await n.run_in_actor(key_error) | ||
|
|
||
| # XXX: originally a bug causes by this | ||
|
||
| # where root would enter debugger even | ||
| # though child should have it locked. | ||
| with trio.fail_after(1): | ||
| await trio.Event().wait() | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| trio.run(main) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -317,32 +317,58 @@ def test_multi_daemon_subactors(spawn, loglevel): | |
| next_msg = name_error_msg | ||
|
|
||
| elif name_error_msg in before: | ||
| next_msg = None | ||
| next_msg = bp_forever_msg | ||
|
|
||
| else: | ||
| raise ValueError("Neither log msg was found !?") | ||
|
|
||
| child.sendline('c') | ||
| # NOTE: previously since we did not have clobber prevention | ||
| # in the root actor this final resume could result in the debugger | ||
| # tearing down since both child actors would be cancelled and it was | ||
| # unlikely that `bp_forever` would re-acquire the tty loack again. | ||
|
||
| # Now, we should have a final resumption in the root plus a possible | ||
| # second entry by `bp_forever`. | ||
|
|
||
| # first name_error failure | ||
| child.sendline('c') | ||
| child.expect(r"\(Pdb\+\+\)") | ||
| before = str(child.before.decode()) | ||
|
|
||
| if next_msg: | ||
| assert next_msg in before | ||
| assert next_msg in before | ||
|
|
||
| child.sendline('c') | ||
| # XXX: hoorayy the root clobering the child here was fixed! | ||
| # IMO, this demonstrates the true power of SC system design. | ||
|
|
||
| child.expect(r"\(Pdb\+\+\)") | ||
| before = str(child.before.decode()) | ||
| assert "tractor._exceptions.RemoteActorError: ('name_error'" in before | ||
| # now the root actor won't clobber the bp_forever child | ||
| # during it's first access to the debug lock, but will instead | ||
| # wait for the lock to release, by the edge triggered | ||
| # ``_debug._no_remote_has_tty`` event before sending cancel messages | ||
| # (via portals) to its underlings B) | ||
|
|
||
| # at some point here there should have been some warning msg from | ||
| # the root announcing it avoided a clobber of the child's lock, but | ||
| # it seems unreliable in testing here to gnab it: | ||
| # assert "in use by child ('bp_forever'," in before | ||
|
|
||
| # wait for final error in root | ||
| while True: | ||
|
|
||
| child.sendline('c') | ||
| child.expect(r"\(Pdb\+\+\)") | ||
| before = str(child.before.decode()) | ||
| try: | ||
|
|
||
| # root error should be packed as remote error | ||
| assert "_exceptions.RemoteActorError: ('name_error'" in before | ||
| break | ||
|
|
||
| except AssertionError: | ||
| assert bp_forever_msg in before | ||
|
|
||
| try: | ||
| child.sendline('c') | ||
| child.expect(pexpect.EOF) | ||
|
|
||
| except pexpect.exceptions.TIMEOUT: | ||
|
|
||
| # Failed to exit using continue..? | ||
| child.sendline('q') | ||
| child.expect(pexpect.EOF) | ||
|
|
@@ -397,7 +423,7 @@ def test_multi_nested_subactors_error_through_nurseries(spawn): | |
| child = spawn('multi_nested_subactors_error_up_through_nurseries') | ||
|
|
||
| # startup time can be iffy | ||
| time.sleep(1) | ||
| # time.sleep(1) | ||
|
||
|
|
||
| for i in range(12): | ||
| try: | ||
|
|
@@ -471,11 +497,34 @@ def test_root_nursery_cancels_before_child_releases_tty_lock( | |
|
|
||
| child.sendline('c') | ||
|
|
||
| child.expect(pexpect.EOF) | ||
| while True: | ||
| try: | ||
| child.expect(pexpect.EOF) | ||
| break | ||
| except pexpect.exceptions.TIMEOUT: | ||
| print('child was ablel to grab tty lock again?') | ||
|
|
||
| if not timed_out_early: | ||
|
|
||
| before = str(child.before.decode()) | ||
| assert "tractor._exceptions.RemoteActorError: ('spawner0'" in before | ||
| assert "tractor._exceptions.RemoteActorError: ('name_error'" in before | ||
| assert "NameError: name 'doggypants' is not defined" in before | ||
|
|
||
|
|
||
| def test_root_cancels_child_context_during_startup( | ||
| spawn, | ||
| ): | ||
| '''Verify a fast fail in the root doesn't lock up the child reaping | ||
| and all while using the new context api. | ||
|
|
||
| ''' | ||
| child = spawn('fast_error_in_root_after_spawn') | ||
|
|
||
| child.expect(r"\(Pdb\+\+\)") | ||
|
|
||
| before = str(child.before.decode()) | ||
| assert "AssertionError" in before | ||
|
|
||
| child.sendline('c') | ||
| child.expect(pexpect.EOF) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo nursery.