forked from goodboy/tractor
				
			Add `Actor.cancel_soon()` for sync self destruct
Add a sync method that can be used to cancel the current actor from a synchronous context. This is useful in debugging situations where sync debugger code may need to kill the process tree. Also, make the internal "lifetime stack" a global var; easier to manage from client code that may was to add callbacks prior to the actor runtime being fully setup.sync_cancel
							parent
							
								
									a13b3fe0a5
								
							
						
					
					
						commit
						be22a2526a
					
				| 
						 | 
				
			
			@ -178,6 +178,10 @@ def _get_mod_abspath(module):
 | 
			
		|||
    return os.path.abspath(module.__file__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# process-global stack closed at end on actor runtime teardown
 | 
			
		||||
_lifetime_stack: ExitStack = ExitStack()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Actor:
 | 
			
		||||
    """The fundamental concurrency primitive.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -192,7 +196,6 @@ class Actor:
 | 
			
		|||
    _root_n: Optional[trio.Nursery] = None
 | 
			
		||||
    _service_n: Optional[trio.Nursery] = None
 | 
			
		||||
    _server_n: Optional[trio.Nursery] = None
 | 
			
		||||
    _lifetime_stack: ExitStack = ExitStack()
 | 
			
		||||
 | 
			
		||||
    # Information about `__main__` from parent
 | 
			
		||||
    _parent_main_data: Dict[str, str]
 | 
			
		||||
| 
						 | 
				
			
			@ -545,8 +548,9 @@ class Actor:
 | 
			
		|||
                    # deadlock and other weird behaviour)
 | 
			
		||||
                    if func != self.cancel:
 | 
			
		||||
                        if isinstance(cs, Exception):
 | 
			
		||||
                            log.warning(f"Task for RPC func {func} failed with"
 | 
			
		||||
                                     f"{cs}")
 | 
			
		||||
                            log.warning(
 | 
			
		||||
                                f"Task for RPC func {func} failed with"
 | 
			
		||||
                                f"{cs}")
 | 
			
		||||
                        else:
 | 
			
		||||
                            # mark that we have ongoing rpc tasks
 | 
			
		||||
                            self._ongoing_rpc_tasks = trio.Event()
 | 
			
		||||
| 
						 | 
				
			
			@ -784,7 +788,7 @@ class Actor:
 | 
			
		|||
            # tear down all lifetime contexts if not in guest mode
 | 
			
		||||
            # XXX: should this just be in the entrypoint?
 | 
			
		||||
            log.warning("Closing all actor lifetime contexts")
 | 
			
		||||
            self._lifetime_stack.close()
 | 
			
		||||
            _lifetime_stack.close()
 | 
			
		||||
 | 
			
		||||
            # Unregister actor from the arbiter
 | 
			
		||||
            if registered_with_arbiter and (
 | 
			
		||||
| 
						 | 
				
			
			@ -858,6 +862,14 @@ class Actor:
 | 
			
		|||
            # signal the server is down since nursery above terminated
 | 
			
		||||
            self._server_down.set()
 | 
			
		||||
 | 
			
		||||
    def cancel_soon(self) -> None:
 | 
			
		||||
        """Cancel this actor asap; can be called from a sync context.
 | 
			
		||||
 | 
			
		||||
        Schedules `.cancel()` to be run immediately just like when
 | 
			
		||||
        cancelled by the parent.
 | 
			
		||||
        """
 | 
			
		||||
        self._service_n.start_soon(self.cancel)
 | 
			
		||||
 | 
			
		||||
    async def cancel(self) -> bool:
 | 
			
		||||
        """Cancel this actor.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue