def stop(self, task_is_resetting=False):
        """
        Stop a task.  This stops all processes for the task.  The approach
        is to mark the task as "stopping" , send a SIGTERM to each process,
        and schedule a SIGKILL for some time later.

        If the legion or task is resetting and a "restart" event is in scope,
        that event will be fired rather than sending the SIGTERM.  Otherwise,
        if a "stop" event is in scope, that event will be fired.  In
        either case, the SIGKILL escalation will still occur so the
        recipient needs to process the event and exit promptly.

        Returns True to request a shorter period before the next call,
        False if nothing special is needed.
    """
        log = self._params.get('log', self._discard)

        if self._stopped:
            log.debug("'%s' is already stopped", self._name)
            return False
        now = time.time()
        running = len(self.get_pids())
        if self._stopping and running == 0:
            log.debug("All '%s' processes are now stopped", self._name)
            self._reset_state()
            self._stopped = now
            return False
        if self._config_running:
            control = self._config_running.get('control')
        else:
            control = None
        if self._terminated:
            #  These are tasks that have been explicitly terminated but have not yet stopped
            #
            if self._killed:
                log.warning("%d '%s' process%s still running %s after SIGKILL escalation",
                            running, self._name, ses(running, 'es'), deltafmt(now - self._killed))
            elif self._terminated + sigkill_escalation < now:
                log.warning("Excalating to SIGKILL with %d '%s' process%s still running",
                            running, self._name, ses(running, 'es'))
                self._signal(signal.SIGKILL)
                self._killed = now
            else:
                log.debug("%d '%s' process%s still running %s after being terminated",
                    running, self._name, ses(running, 'es'), deltafmt(now - self._terminated))
            return True
        if self._limit and now > self._limit:
            #  These are tasks that have a time limit set and it has expired.
            #  This case falls through to the stop code.
            log.info("Stopping task '%s', time limit exceeded %s ago", self._name, deltafmt(now - self._limit))
        elif self._stopping and not self._legion.is_exiting():
            #  These are tasks that are expected to stop soon but have not been explicitly
            #  terminated.  These are typically tasks with 'once' or 'event' controls.
            #  Unless there is a time limit set, they are allowed to run indefinitely
            #
            log.debug("%d '%s' '%s' process%s still running %s",
                    running, self._name, control, ses(running, 'es'), deltafmt(now - self._stopping))
            return False

        if not self._stopping:
            self._stopping = now
        self._terminated = now
        restart_target = None
        stop_target = None
        resetting = self._legion.is_resetting() or task_is_resetting
        if self._config_running:
            for event in self._config_running.get('events', []):
                ev_type = self._get(event.get('type'))
                if resetting and ev_type == 'restart':
                    restart_target = self._make_event_target(event, control)
                elif ev_type == 'stop':
                    stop_target = self._make_event_target(event, control)
        if restart_target:
            log.debug("Restart event on %d '%s' process%s", running, self._name, ses(running, 'es'))
            restart_target.handle()
        elif stop_target:
            log.debug("Stop event on %d '%s' process%s", running, self._name, ses(running, 'es'))
            stop_target.handle()
        else:
            log.debug("Stopping %d '%s' process%s with SIGTERM", running, self._name, ses(running, 'es'))
            self._signal(signal.SIGTERM)
        return True
def stop ( self , task_is_resetting = False ) : log = self . _params . get ( 'log' , self . _discard ) if self . _stopped : log . debug ( "'%s' is already stopped" , self . _name ) return False now = time . time ( ) running = len ( self . get_pids ( ) ) if self . _stopping and running == 0 : log . debug ( "All '%s' processes are now stopped" , self . _name ) self . _reset_state ( ) self . _stopped = now return False if self . _config_running : control = self . _config_running . get ( 'control' ) else : control = None if self . _terminated : if self . _killed : log . warning ( "%d '%s' process%s still running %s after SIGKILL escalation" , running , self . _name , ses ( running , 'es' ) , deltafmt ( now - self . _killed ) ) elif self . _terminated + sigkill_escalation < now : log . warning ( "Excalating to SIGKILL with %d '%s' process%s still running" , running , self . _name , ses ( running , 'es' ) ) self . _signal ( signal . SIGKILL ) self . _killed = now else : log . debug ( "%d '%s' process%s still running %s after being terminated" , running , self . _name , ses ( running , 'es' ) , deltafmt ( now - self . _terminated ) ) return True if self . _limit and now > self . _limit : log . info ( "Stopping task '%s', time limit exceeded %s ago" , self . _name , deltafmt ( now - self . _limit ) ) elif self . _stopping and not self . _legion . is_exiting ( ) : log . debug ( "%d '%s' '%s' process%s still running %s" , running , self . _name , control , ses ( running , 'es' ) , deltafmt ( now - self . _stopping ) ) return False if not self . _stopping : self . _stopping = now self . _terminated = now restart_target = None stop_target = None resetting = self . _legion . is_resetting ( ) or task_is_resetting if self . _config_running : for event in self . _config_running . get ( 'events' , [ ] ) : ev_type = self . _get ( event . get ( 'type' ) ) if resetting and ev_type == 'restart' : restart_target = self . _make_event_target ( event , control ) elif ev_type == 'stop' : stop_target = self . _make_event_target ( event , control ) if restart_target : log . debug ( "Restart event on %d '%s' process%s" , running , self . _name , ses ( running , 'es' ) ) restart_target . handle ( ) elif stop_target : log . debug ( "Stop event on %d '%s' process%s" , running , self . _name , ses ( running , 'es' ) ) stop_target . handle ( ) else : log . debug ( "Stopping %d '%s' process%s with SIGTERM" , running , self . _name , ses ( running , 'es' ) ) self . _signal ( signal . SIGTERM ) return True
Stop a task.  This stops all processes for the task.  The approach
        is to mark the task as "stopping" , send a SIGTERM to each process,
        and schedule a SIGKILL for some time later.

        If the legion or task is resetting and a "restart" event is in scope,
        that event will be fired rather than sending the SIGTERM.  Otherwise,
        if a "stop" event is in scope, that event will be fired.  In
        either case, the SIGKILL escalation will still occur so the
        recipient needs to process the event and exit promptly.

        Returns True to request a shorter period before the next call,
        False if nothing special is needed.