prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  St2Stream service broken when using SSL with mongodb
  ## SUMMARY
  
  This issue is an extension to #4832 however this time it is the st2stream service, I have looked that the code and can see the same monkey patch code hasn't been applied to the st2stream app
  
  ### STACKSTORM VERSION
  
  Paste the output of ``st2 --version``: 3.3.0
  
  ##### OS, environment, install method
  
  Docker compose with the split services and mongo db references commented out so that an external db can be used  https://github.com/StackStorm/st2-docker/blob/master/docker-compose.yml
  
  All other services correctly connected to mongodb.net test instance with the exception of st2stream.
  
  ## Steps to reproduce the problem
  
  use docker yaml at https://github.com/StackStorm/st2-docker/blob/master/docker-compose.yml, comment out mongo container and references, adjust files/st2-docker.conf to point to external DB with SSL = True enabled.
  docker-compose up
  
  ## Expected Results
  
  What did you expect to happen when running the steps above?
  
  st2stream to operate correctly
  
  ## Actual Results
  
  What happened? What output did you get?
  
  2020-11-16 05:48:55,053 WARNING [-] Retry on ConnectionError - Cannot connect to database default :
  maximum recursion depth exceeded
  
  
  
  Adding monkey patch code to st2stream app resolves the issue (manually injected into container to test).
  
  file:   st2stream/cmd/api.py
  Code: 
  from st2common.util.monkey_patch import monkey_patch
  monkey_patch()
  
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `st2stream/st2stream/cmd/api.py`
  Content:
  ```
  1 # Copyright 2020 The StackStorm Authors.
  2 # Copyright 2019 Extreme Networks, Inc.
  3 #
  4 # Licensed under the Apache License, Version 2.0 (the "License");
  5 # you may not use this file except in compliance with the License.
  6 # You may obtain a copy of the License at
  7 #
  8 #     http://www.apache.org/licenses/LICENSE-2.0
  9 #
  10 # Unless required by applicable law or agreed to in writing, software
  11 # distributed under the License is distributed on an "AS IS" BASIS,
  12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 # See the License for the specific language governing permissions and
  14 # limitations under the License.
  15 
  16 import os
  17 import sys
  18 
  19 import eventlet
  20 from oslo_config import cfg
  21 from eventlet import wsgi
  22 
  23 from st2common import log as logging
  24 from st2common.service_setup import setup as common_setup
  25 from st2common.service_setup import teardown as common_teardown
  26 from st2common.stream.listener import get_listener_if_set
  27 from st2common.util.wsgi import shutdown_server_kill_pending_requests
  28 from st2stream.signal_handlers import register_stream_signal_handlers
  29 from st2stream import config
  30 config.register_opts()
  31 from st2stream import app
  32 
  33 __all__ = [
  34     'main'
  35 ]
  36 
  37 
  38 eventlet.monkey_patch(
  39     os=True,
  40     select=True,
  41     socket=True,
  42     thread=False if '--use-debugger' in sys.argv else True,
  43     time=True)
  44 
  45 LOG = logging.getLogger(__name__)
  46 
  47 # How much time to give to the request in progress to finish in seconds before killing them
  48 WSGI_SERVER_REQUEST_SHUTDOWN_TIME = 2
  49 
  50 
  51 def _setup():
  52     capabilities = {
  53         'name': 'stream',
  54         'listen_host': cfg.CONF.stream.host,
  55         'listen_port': cfg.CONF.stream.port,
  56         'type': 'active'
  57     }
  58     common_setup(service='stream', config=config, setup_db=True, register_mq_exchanges=True,
  59                  register_signal_handlers=True, register_internal_trigger_types=False,
  60                  run_migrations=False, service_registry=True, capabilities=capabilities)
  61 
  62 
  63 def _run_server():
  64     host = cfg.CONF.stream.host
  65     port = cfg.CONF.stream.port
  66 
  67     LOG.info('(PID=%s) ST2 Stream API is serving on http://%s:%s.', os.getpid(), host, port)
  68 
  69     max_pool_size = eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS
  70     worker_pool = eventlet.GreenPool(max_pool_size)
  71     sock = eventlet.listen((host, port))
  72 
  73     def queue_shutdown(signal_number, stack_frame):
  74         eventlet.spawn_n(shutdown_server_kill_pending_requests, sock=sock,
  75                          worker_pool=worker_pool, wait_time=WSGI_SERVER_REQUEST_SHUTDOWN_TIME)
  76 
  77     # We register a custom SIGINT handler which allows us to kill long running active requests.
  78     # Note: Eventually we will support draining (waiting for short-running requests), but we
  79     # will still want to kill long running stream requests.
  80     register_stream_signal_handlers(handler_func=queue_shutdown)
  81 
  82     wsgi.server(sock, app.setup_app(), custom_pool=worker_pool)
  83     return 0
  84 
  85 
  86 def _teardown():
  87     common_teardown()
  88 
  89 
  90 def main():
  91     try:
  92         _setup()
  93         return _run_server()
  94     except SystemExit as exit_code:
  95         sys.exit(exit_code)
  96     except KeyboardInterrupt:
  97         listener = get_listener_if_set(name='stream')
  98 
  99         if listener:
  100             listener.shutdown()
  101     except Exception:
  102         LOG.exception('(PID=%s) ST2 Stream API quit due to exception.', os.getpid())
  103         return 1
  104     finally:
  105         _teardown()
  106
  ```
  --- 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/st2stream/st2stream/cmd/api.py b/st2stream/st2stream/cmd/api.py
  --- a/st2stream/st2stream/cmd/api.py
  +++ b/st2stream/st2stream/cmd/api.py
  @@ -13,6 +13,9 @@
   # See the License for the specific language governing permissions and
   # limitations under the License.
   
  +from st2common.util.monkey_patch import monkey_patch
  +monkey_patch()
  +
   import os
   import sys
  
verification_info: {"golden_diff": "diff --git a/st2stream/st2stream/cmd/api.py b/st2stream/st2stream/cmd/api.py\n--- a/st2stream/st2stream/cmd/api.py\n+++ b/st2stream/st2stream/cmd/api.py\n@@ -13,6 +13,9 @@\n # See the License for the specific language governing permissions and\n # limitations under the License.\n \n+from st2common.util.monkey_patch import monkey_patch\n+monkey_patch()\n+\n import os\n import sys\n", "issue": "St2Stream service broken when using SSL with mongodb\n## SUMMARY\r\n\r\nThis issue is an extension to #4832 however this time it is the st2stream service, I have looked that the code and can see the same monkey patch code hasn't been applied to the st2stream app\r\n\r\n### STACKSTORM VERSION\r\n\r\nPaste the output of ``st2 --version``: 3.3.0\r\n\r\n##### OS, environment, install method\r\n\r\nDocker compose with the split services and mongo db references commented out so that an external db can be used  https://github.com/StackStorm/st2-docker/blob/master/docker-compose.yml\r\n\r\nAll other services correctly connected to mongodb.net test instance with the exception of st2stream.\r\n\r\n## Steps to reproduce the problem\r\n\r\nuse docker yaml at https://github.com/StackStorm/st2-docker/blob/master/docker-compose.yml, comment out mongo container and references, adjust files/st2-docker.conf to point to external DB with SSL = True enabled.\r\ndocker-compose up\r\n\r\n## Expected Results\r\n\r\nWhat did you expect to happen when running the steps above?\r\n\r\nst2stream to operate correctly\r\n\r\n## Actual Results\r\n\r\nWhat happened? What output did you get?\r\n\r\n2020-11-16 05:48:55,053 WARNING [-] Retry on ConnectionError - Cannot connect to database default :\r\nmaximum recursion depth exceeded\r\n\r\n\r\n\r\nAdding monkey patch code to st2stream app resolves the issue (manually injected into container to test).\r\n\r\nfile:   st2stream/cmd/api.py\r\nCode: \r\nfrom st2common.util.monkey_patch import monkey_patch\r\nmonkey_patch()\r\n\r\n\n", "before_files": [{"content": "# Copyright 2020 The StackStorm Authors.\n# Copyright 2019 Extreme Networks, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport sys\n\nimport eventlet\nfrom oslo_config import cfg\nfrom eventlet import wsgi\n\nfrom st2common import log as logging\nfrom st2common.service_setup import setup as common_setup\nfrom st2common.service_setup import teardown as common_teardown\nfrom st2common.stream.listener import get_listener_if_set\nfrom st2common.util.wsgi import shutdown_server_kill_pending_requests\nfrom st2stream.signal_handlers import register_stream_signal_handlers\nfrom st2stream import config\nconfig.register_opts()\nfrom st2stream import app\n\n__all__ = [\n    'main'\n]\n\n\neventlet.monkey_patch(\n    os=True,\n    select=True,\n    socket=True,\n    thread=False if '--use-debugger' in sys.argv else True,\n    time=True)\n\nLOG = logging.getLogger(__name__)\n\n# How much time to give to the request in progress to finish in seconds before killing them\nWSGI_SERVER_REQUEST_SHUTDOWN_TIME = 2\n\n\ndef _setup():\n    capabilities = {\n        'name': 'stream',\n        'listen_host': cfg.CONF.stream.host,\n        'listen_port': cfg.CONF.stream.port,\n        'type': 'active'\n    }\n    common_setup(service='stream', config=config, setup_db=True, register_mq_exchanges=True,\n                 register_signal_handlers=True, register_internal_trigger_types=False,\n                 run_migrations=False, service_registry=True, capabilities=capabilities)\n\n\ndef _run_server():\n    host = cfg.CONF.stream.host\n    port = cfg.CONF.stream.port\n\n    LOG.info('(PID=%s) ST2 Stream API is serving on http://%s:%s.', os.getpid(), host, port)\n\n    max_pool_size = eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS\n    worker_pool = eventlet.GreenPool(max_pool_size)\n    sock = eventlet.listen((host, port))\n\n    def queue_shutdown(signal_number, stack_frame):\n        eventlet.spawn_n(shutdown_server_kill_pending_requests, sock=sock,\n                         worker_pool=worker_pool, wait_time=WSGI_SERVER_REQUEST_SHUTDOWN_TIME)\n\n    # We register a custom SIGINT handler which allows us to kill long running active requests.\n    # Note: Eventually we will support draining (waiting for short-running requests), but we\n    # will still want to kill long running stream requests.\n    register_stream_signal_handlers(handler_func=queue_shutdown)\n\n    wsgi.server(sock, app.setup_app(), custom_pool=worker_pool)\n    return 0\n\n\ndef _teardown():\n    common_teardown()\n\n\ndef main():\n    try:\n        _setup()\n        return _run_server()\n    except SystemExit as exit_code:\n        sys.exit(exit_code)\n    except KeyboardInterrupt:\n        listener = get_listener_if_set(name='stream')\n\n        if listener:\n            listener.shutdown()\n    except Exception:\n        LOG.exception('(PID=%s) ST2 Stream API quit due to exception.', os.getpid())\n        return 1\n    finally:\n        _teardown()\n", "path": "st2stream/st2stream/cmd/api.py"}], "after_files": [{"content": "# Copyright 2020 The StackStorm Authors.\n# Copyright 2019 Extreme Networks, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom st2common.util.monkey_patch import monkey_patch\nmonkey_patch()\n\nimport os\nimport sys\n\nimport eventlet\nfrom oslo_config import cfg\nfrom eventlet import wsgi\n\nfrom st2common import log as logging\nfrom st2common.service_setup import setup as common_setup\nfrom st2common.service_setup import teardown as common_teardown\nfrom st2common.stream.listener import get_listener_if_set\nfrom st2common.util.wsgi import shutdown_server_kill_pending_requests\nfrom st2stream.signal_handlers import register_stream_signal_handlers\nfrom st2stream import config\nconfig.register_opts()\nfrom st2stream import app\n\n__all__ = [\n    'main'\n]\n\n\neventlet.monkey_patch(\n    os=True,\n    select=True,\n    socket=True,\n    thread=False if '--use-debugger' in sys.argv else True,\n    time=True)\n\nLOG = logging.getLogger(__name__)\n\n# How much time to give to the request in progress to finish in seconds before killing them\nWSGI_SERVER_REQUEST_SHUTDOWN_TIME = 2\n\n\ndef _setup():\n    capabilities = {\n        'name': 'stream',\n        'listen_host': cfg.CONF.stream.host,\n        'listen_port': cfg.CONF.stream.port,\n        'type': 'active'\n    }\n    common_setup(service='stream', config=config, setup_db=True, register_mq_exchanges=True,\n                 register_signal_handlers=True, register_internal_trigger_types=False,\n                 run_migrations=False, service_registry=True, capabilities=capabilities)\n\n\ndef _run_server():\n    host = cfg.CONF.stream.host\n    port = cfg.CONF.stream.port\n\n    LOG.info('(PID=%s) ST2 Stream API is serving on http://%s:%s.', os.getpid(), host, port)\n\n    max_pool_size = eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS\n    worker_pool = eventlet.GreenPool(max_pool_size)\n    sock = eventlet.listen((host, port))\n\n    def queue_shutdown(signal_number, stack_frame):\n        eventlet.spawn_n(shutdown_server_kill_pending_requests, sock=sock,\n                         worker_pool=worker_pool, wait_time=WSGI_SERVER_REQUEST_SHUTDOWN_TIME)\n\n    # We register a custom SIGINT handler which allows us to kill long running active requests.\n    # Note: Eventually we will support draining (waiting for short-running requests), but we\n    # will still want to kill long running stream requests.\n    register_stream_signal_handlers(handler_func=queue_shutdown)\n\n    wsgi.server(sock, app.setup_app(), custom_pool=worker_pool)\n    return 0\n\n\ndef _teardown():\n    common_teardown()\n\n\ndef main():\n    try:\n        _setup()\n        return _run_server()\n    except SystemExit as exit_code:\n        sys.exit(exit_code)\n    except KeyboardInterrupt:\n        listener = get_listener_if_set(name='stream')\n\n        if listener:\n            listener.shutdown()\n    except Exception:\n        LOG.exception('(PID=%s) ST2 Stream API quit due to exception.', os.getpid())\n        return 1\n    finally:\n        _teardown()\n", "path": "st2stream/st2stream/cmd/api.py"}]}