prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Connectors should fork
  When a connector is started it should fork into its own process. This is because connectors block to accept messages from their source.
  
  This requires #5 to enable persistent memory between connector processes.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `opsdroid/core.py`
  Content:
  ```
  1 """Core components of OpsDroid."""
  2 
  3 import logging
  4 import sys
  5 import weakref
  6 from opsdroid.helper import match
  7 from opsdroid.memory import Memory
  8 
  9 
  10 class OpsDroid():
  11     """Root object for opsdroid."""
  12 
  13     instances = []
  14 
  15     def __init__(self):
  16         """Start opsdroid."""
  17         self.bot_name = 'opsdroid'
  18         self.sys_status = 0
  19         self.connectors = []
  20         self.skills = []
  21         self.memory = Memory()
  22         logging.info("Created main opsdroid object")
  23 
  24     def __enter__(self):
  25         """Add self to existing instances."""
  26         if len(self.__class__.instances) == 0:
  27             self.__class__.instances.append(weakref.proxy(self))
  28         else:
  29             self.critical("opsdroid has already been started", 1)
  30         return self
  31 
  32     def __exit__(self, exc_type, exc_value, traceback):
  33         """Remove self from existing instances."""
  34         self.__class__.instances = []
  35 
  36     def exit(self):
  37         """Exit application."""
  38         logging.info("Exiting application with return code " +
  39                      str(self.sys_status))
  40         sys.exit(self.sys_status)
  41 
  42     def critical(self, error, code):
  43         """Exit due to unrecoverable error."""
  44         self.sys_status = code
  45         logging.critical(error)
  46         print("Error: " + error)
  47         self.exit()
  48 
  49     def start_connectors(self, connectors):
  50         """Start the connectors."""
  51         if len(connectors) == 0:
  52             self.critical("All connectors failed to load", 1)
  53         for connector_module in connectors:
  54             for name, cls in connector_module["module"].__dict__.items():
  55                 if isinstance(cls, type) and "Connector" in name:
  56                     connector_module["config"]["bot-name"] = self.bot_name
  57                     connector = cls(connector_module["config"])
  58                     self.connectors.append(connector)
  59                     connector.connect(self)
  60 
  61     def start_databases(self, databases):
  62         """Start the databases."""
  63         if len(databases) == 0:
  64             logging.warning("All databases failed to load")
  65         for database_module in databases:
  66             for name, cls in database_module["module"].__dict__.items():
  67                 if isinstance(cls, type) and "Database" in name:
  68                     logging.debug("Adding database: " + name)
  69                     database = cls(database_module["config"])
  70                     self.memory.databases.append(database)
  71                     database.connect()
  72 
  73     def load_regex_skill(self, regex, skill):
  74         """Load skills."""
  75         self.skills.append({"regex": regex, "skill": skill})
  76 
  77     def parse(self, message):
  78         """Parse a string against all skills."""
  79         if message.text.strip() != "":
  80             logging.debug("Parsing input: " + message.text)
  81             for skill in self.skills:
  82                 if "regex" in skill:
  83                     regex = match(skill["regex"], message.text)
  84                     if regex:
  85                         message.regex = regex
  86                         skill["skill"](self, message)
  87
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/opsdroid/core.py b/opsdroid/core.py
  --- a/opsdroid/core.py
  +++ b/opsdroid/core.py
  @@ -3,6 +3,7 @@
   import logging
   import sys
   import weakref
  +from multiprocessing import Process
   from opsdroid.helper import match
   from opsdroid.memory import Memory
   
  @@ -17,6 +18,7 @@
           self.bot_name = 'opsdroid'
           self.sys_status = 0
           self.connectors = []
  +        self.connector_jobs = []
           self.skills = []
           self.memory = Memory()
           logging.info("Created main opsdroid object")
  @@ -56,7 +58,11 @@
                       connector_module["config"]["bot-name"] = self.bot_name
                       connector = cls(connector_module["config"])
                       self.connectors.append(connector)
  -                    connector.connect(self)
  +                    job = Process(target=connector.connect, args=(self,))
  +                    job.start()
  +                    self.connector_jobs.append(job)
  +        for job in self.connector_jobs:
  +            job.join()
   
       def start_databases(self, databases):
           """Start the databases."""
  
verification_info: {"golden_diff": "diff --git a/opsdroid/core.py b/opsdroid/core.py\n--- a/opsdroid/core.py\n+++ b/opsdroid/core.py\n@@ -3,6 +3,7 @@\n import logging\n import sys\n import weakref\n+from multiprocessing import Process\n from opsdroid.helper import match\n from opsdroid.memory import Memory\n \n@@ -17,6 +18,7 @@\n         self.bot_name = 'opsdroid'\n         self.sys_status = 0\n         self.connectors = []\n+        self.connector_jobs = []\n         self.skills = []\n         self.memory = Memory()\n         logging.info(\"Created main opsdroid object\")\n@@ -56,7 +58,11 @@\n                     connector_module[\"config\"][\"bot-name\"] = self.bot_name\n                     connector = cls(connector_module[\"config\"])\n                     self.connectors.append(connector)\n-                    connector.connect(self)\n+                    job = Process(target=connector.connect, args=(self,))\n+                    job.start()\n+                    self.connector_jobs.append(job)\n+        for job in self.connector_jobs:\n+            job.join()\n \n     def start_databases(self, databases):\n         \"\"\"Start the databases.\"\"\"\n", "issue": "Connectors should fork\nWhen a connector is started it should fork into its own process. This is because connectors block to accept messages from their source.\n\nThis requires #5 to enable persistent memory between connector processes.\n\n", "before_files": [{"content": "\"\"\"Core components of OpsDroid.\"\"\"\n\nimport logging\nimport sys\nimport weakref\nfrom opsdroid.helper import match\nfrom opsdroid.memory import Memory\n\n\nclass OpsDroid():\n    \"\"\"Root object for opsdroid.\"\"\"\n\n    instances = []\n\n    def __init__(self):\n        \"\"\"Start opsdroid.\"\"\"\n        self.bot_name = 'opsdroid'\n        self.sys_status = 0\n        self.connectors = []\n        self.skills = []\n        self.memory = Memory()\n        logging.info(\"Created main opsdroid object\")\n\n    def __enter__(self):\n        \"\"\"Add self to existing instances.\"\"\"\n        if len(self.__class__.instances) == 0:\n            self.__class__.instances.append(weakref.proxy(self))\n        else:\n            self.critical(\"opsdroid has already been started\", 1)\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        \"\"\"Remove self from existing instances.\"\"\"\n        self.__class__.instances = []\n\n    def exit(self):\n        \"\"\"Exit application.\"\"\"\n        logging.info(\"Exiting application with return code \" +\n                     str(self.sys_status))\n        sys.exit(self.sys_status)\n\n    def critical(self, error, code):\n        \"\"\"Exit due to unrecoverable error.\"\"\"\n        self.sys_status = code\n        logging.critical(error)\n        print(\"Error: \" + error)\n        self.exit()\n\n    def start_connectors(self, connectors):\n        \"\"\"Start the connectors.\"\"\"\n        if len(connectors) == 0:\n            self.critical(\"All connectors failed to load\", 1)\n        for connector_module in connectors:\n            for name, cls in connector_module[\"module\"].__dict__.items():\n                if isinstance(cls, type) and \"Connector\" in name:\n                    connector_module[\"config\"][\"bot-name\"] = self.bot_name\n                    connector = cls(connector_module[\"config\"])\n                    self.connectors.append(connector)\n                    connector.connect(self)\n\n    def start_databases(self, databases):\n        \"\"\"Start the databases.\"\"\"\n        if len(databases) == 0:\n            logging.warning(\"All databases failed to load\")\n        for database_module in databases:\n            for name, cls in database_module[\"module\"].__dict__.items():\n                if isinstance(cls, type) and \"Database\" in name:\n                    logging.debug(\"Adding database: \" + name)\n                    database = cls(database_module[\"config\"])\n                    self.memory.databases.append(database)\n                    database.connect()\n\n    def load_regex_skill(self, regex, skill):\n        \"\"\"Load skills.\"\"\"\n        self.skills.append({\"regex\": regex, \"skill\": skill})\n\n    def parse(self, message):\n        \"\"\"Parse a string against all skills.\"\"\"\n        if message.text.strip() != \"\":\n            logging.debug(\"Parsing input: \" + message.text)\n            for skill in self.skills:\n                if \"regex\" in skill:\n                    regex = match(skill[\"regex\"], message.text)\n                    if regex:\n                        message.regex = regex\n                        skill[\"skill\"](self, message)\n", "path": "opsdroid/core.py"}], "after_files": [{"content": "\"\"\"Core components of OpsDroid.\"\"\"\n\nimport logging\nimport sys\nimport weakref\nfrom multiprocessing import Process\nfrom opsdroid.helper import match\nfrom opsdroid.memory import Memory\n\n\nclass OpsDroid():\n    \"\"\"Root object for opsdroid.\"\"\"\n\n    instances = []\n\n    def __init__(self):\n        \"\"\"Start opsdroid.\"\"\"\n        self.bot_name = 'opsdroid'\n        self.sys_status = 0\n        self.connectors = []\n        self.connector_jobs = []\n        self.skills = []\n        self.memory = Memory()\n        logging.info(\"Created main opsdroid object\")\n\n    def __enter__(self):\n        \"\"\"Add self to existing instances.\"\"\"\n        if len(self.__class__.instances) == 0:\n            self.__class__.instances.append(weakref.proxy(self))\n        else:\n            self.critical(\"opsdroid has already been started\", 1)\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        \"\"\"Remove self from existing instances.\"\"\"\n        self.__class__.instances = []\n\n    def exit(self):\n        \"\"\"Exit application.\"\"\"\n        logging.info(\"Exiting application with return code \" +\n                     str(self.sys_status))\n        sys.exit(self.sys_status)\n\n    def critical(self, error, code):\n        \"\"\"Exit due to unrecoverable error.\"\"\"\n        self.sys_status = code\n        logging.critical(error)\n        print(\"Error: \" + error)\n        self.exit()\n\n    def start_connectors(self, connectors):\n        \"\"\"Start the connectors.\"\"\"\n        if len(connectors) == 0:\n            self.critical(\"All connectors failed to load\", 1)\n        for connector_module in connectors:\n            for name, cls in connector_module[\"module\"].__dict__.items():\n                if isinstance(cls, type) and \"Connector\" in name:\n                    connector_module[\"config\"][\"bot-name\"] = self.bot_name\n                    connector = cls(connector_module[\"config\"])\n                    self.connectors.append(connector)\n                    job = Process(target=connector.connect, args=(self,))\n                    job.start()\n                    self.connector_jobs.append(job)\n        for job in self.connector_jobs:\n            job.join()\n\n    def start_databases(self, databases):\n        \"\"\"Start the databases.\"\"\"\n        if len(databases) == 0:\n            logging.warning(\"All databases failed to load\")\n        for database_module in databases:\n            for name, cls in database_module[\"module\"].__dict__.items():\n                if isinstance(cls, type) and \"Database\" in name:\n                    logging.debug(\"Adding database: \" + name)\n                    database = cls(database_module[\"config\"])\n                    self.memory.databases.append(database)\n                    database.connect()\n\n    def load_regex_skill(self, regex, skill):\n        \"\"\"Load skills.\"\"\"\n        self.skills.append({\"regex\": regex, \"skill\": skill})\n\n    def parse(self, message):\n        \"\"\"Parse a string against all skills.\"\"\"\n        if message.text.strip() != \"\":\n            logging.debug(\"Parsing input: \" + message.text)\n            for skill in self.skills:\n                if \"regex\" in skill:\n                    regex = match(skill[\"regex\"], message.text)\n                    if regex:\n                        message.regex = regex\n                        skill[\"skill\"](self, message)\n", "path": "opsdroid/core.py"}]}