Repository: MycroftAI/mycroft-core

Issue:
Skills and Enclosure background services fail to stop and are killed...
## Be clear about the software, hardware and version you are running

For example: 

in CLI
 >> what version are you running                                                                                                                                               
 >> I am running mycroft-core version 20 oh 2, release 0                                                                                                                    
 >> You are on the latest version.

Opensuse Leap 15.1
## Try to provide steps that we can use to replicate the Issue

For example: 

1. CTRL+C in CLI
2. Enter ./stop_mycroft.sh 
3. Skills and Enclosure services are eventually killed.
4. Takes about 30 seconds total

## Be as specific as possible about the expected condition, and the deviation from expected condition. 

user@LinuxOS:~/mycroft-core> ./stop-mycroft.sh skills
Stopping skills (5579)...stopped.
user@LinuxOS:~/mycroft-core> ./stop-mycroft.sh enclosure
Stopping enclosure (5588)...failed to stop.
  Killing enclosure (5588)...killed.
user@LinuxOS:~/mycroft-core> ./stop-mycroft.sh
Stopping all mycroft-core services
Stopping messagebus.service (5576)...stopped.
Stopping audio (5582)...stopped.
Stopping speech (5585)...stopped.
...
user@LinuxOS:~/mycroft-core> ./stop-mycroft.sh
Stopping all mycroft-core services
Stopping messagebus.service (18995)...stopped.
Stopping skills (18998)...failed to stop.
  Killing skills (18998)...killed.
Stopping audio (19001)...stopped.
Stopping speech (19004)...stopped.
Stopping enclosure (19007)...failed to stop.
  Killing enclosure (19007)...killed.
user@LinuxOS:~/mycroft-core> 




Discussion:
As I see this - it only kills the skillsservice if it takes to long to stop. The reason for a long stop time could be a bad skill hangs or a skill is dooing something that takes long time when it gets the shutdown command.

I think killing the service is the right to do if it takes to long - I notised that if one is making some bad programming in a skill (i do that all the time) then the skill will not liad, and if it is really bad skillservice will hang ending up wuith mycroft answers "waite until i finish booting up".
And then restarting skillservice hangs until the restart is killing the process. 

I have never seen los of data, and have heavily used killing the proces when I worked on injecting debug adaptor. 

So I think killing proceses is fine, but first ask nicely as it is alreddy done. but maybe the timeout until killing should be encresed.
As @andlo says in some cases the killing is valid and I've seen no real harm from it yet but there are potential for harm.

Things that could be improved
- shutting down during msm install. (this could theoretically cause issues)
- shutting down while uploading settings meta.
- shutting down while doing the initial load of skills.

And the enclosure, there's no need for it to be all that busy. It should basically never need to be killed so there's probably a bug there.
Okay, this is what I understand that I need to do. I should wait until the "I'm finished booting up." message pops up BEFORE I shut down the services. I don't remember if that's when I tried to shut down the services. I will report later what happened. Thanks!!!!
I got this message: ">> Hi, this is mycroft and I am ready to work." BUT there was MSM messages still scrolling past so I waited until the messages stopped. Skills and Enclosure both were killed.
I've always had this problem with the enclosure service, but only recently started seeing it with skills. I assumed it was because the enclosure isn't fully implemented on Linux (which has no associated hardware, ofc.)

I've just tested on a clean installation, which still needed to kill the skills service. I edited stop-mycroft.sh and upped the timeout to 30 seconds, and the skill service did eventually stop, though I didn't count how long it took.
Thanks @ChanceNCounter . I tried 30 and 60 seconds, both fixed the skills error which took 10 seconds to stop, but the enclosure did not stop after 60 seconds. I will try 120 seconds, but if that doesn't work, I don't know what to do.
120 seconds caused (or maybe my impatience caused) the message bus not to stop even past the 120 second mark and it would not move on to be killed or stopped. I thought I messed something up, so I rebooted the PC and tried again. It did the same thing. I had to CTRL+C on it to move on both times. So I changed the time out to 15 seconds and now it works except for enclosure is killed.
Thanks for testing @trekjunky, there may be some regression here causing it to lock up during shutdown more than it should. We should definitely investigate more and see what's causing this.

Resolving patch:
diff --git a/mycroft/client/enclosure/__main__.py b/mycroft/client/enclosure/__main__.py
--- a/mycroft/client/enclosure/__main__.py
+++ b/mycroft/client/enclosure/__main__.py
@@ -12,44 +12,67 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-import sys
+"""Entrypoint for enclosure service.
 
+This provides any "enclosure" specific functionality, for example GUI or
+control over the Mark-1 Faceplate.
+"""
+from mycroft.configuration import LocalConf, SYSTEM_CONFIG
 from mycroft.util.log import LOG
-from mycroft.messagebus.client import MessageBusClient
-from mycroft.configuration import Configuration, LocalConf, SYSTEM_CONFIG
+from mycroft.util import (create_daemon, wait_for_exit_signal,
+                          reset_sigint_handler)
 
 
-def main():
-    # Read the system configuration
-    system_config = LocalConf(SYSTEM_CONFIG)
-    platform = system_config.get("enclosure", {}).get("platform")
+def create_enclosure(platform):
+    """Create an enclosure based on the provided platform string.
 
+    Arguments:
+        platform (str): platform name string
+
+    Returns:
+        Enclosure object
+    """
     if platform == "mycroft_mark_1":
-        LOG.debug("Creating Mark I Enclosure")
+        LOG.info("Creating Mark I Enclosure")
         from mycroft.client.enclosure.mark1 import EnclosureMark1
         enclosure = EnclosureMark1()
     elif platform == "mycroft_mark_2":
-        LOG.debug("Creating Mark II Enclosure")
+        LOG.info("Creating Mark II Enclosure")
         from mycroft.client.enclosure.mark2 import EnclosureMark2
         enclosure = EnclosureMark2()
     else:
-        LOG.debug("Creating generic enclosure, platform='{}'".format(platform))
+        LOG.info("Creating generic enclosure, platform='{}'".format(platform))
 
         # TODO: Mechanism to load from elsewhere.  E.g. read a script path from
         # the mycroft.conf, then load/launch that script.
         from mycroft.client.enclosure.generic import EnclosureGeneric
         enclosure = EnclosureGeneric()
 
+    return enclosure
+
+
+def main():
+    """Launch one of the available enclosure implementations.
+
+    This depends on the configured platform and can currently either be
+    mycroft_mark_1 or mycroft_mark_2, if unconfigured a generic enclosure with
+    only the GUI bus will be started.
+    """
+    # Read the system configuration
+    system_config = LocalConf(SYSTEM_CONFIG)
+    platform = system_config.get("enclosure", {}).get("platform")
+
+    enclosure = create_enclosure(platform)
     if enclosure:
         try:
             LOG.debug("Enclosure started!")
-            enclosure.run()
+            reset_sigint_handler()
+            create_daemon(enclosure.run)
+            wait_for_exit_signal()
         except Exception as e:
             print(e)
-        finally:
-            sys.exit()
     else:
-        LOG.debug("No enclosure available for this hardware, running headless")
+        LOG.info("No enclosure available for this hardware, running headless")
 
 
 if __name__ == "__main__":


Test patch: