From 75af8a30984d85c1e3bd78823e52816064f831c2 Mon Sep 17 00:00:00 2001 From: Jacob Zufelt Date: Tue, 24 Feb 2026 12:16:33 -0700 Subject: [PATCH 1/5] wsgi WIP --- st2common/st2common/util/concurrency.py | 22 ++++++++++++++++++++++ st2common/st2common/util/monkey_patch.py | 7 +++++-- st2stream/st2stream/cmd/api.py | 22 ++++++++++++---------- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/st2common/st2common/util/concurrency.py b/st2common/st2common/util/concurrency.py index 150d088036..f064be4292 100644 --- a/st2common/st2common/util/concurrency.py +++ b/st2common/st2common/util/concurrency.py @@ -140,6 +140,16 @@ def get_greenlet_exit_exception_class(): raise ValueError("Unsupported concurrency library") +def get_default_green_pool_size(): + if CONCURRENCY_LIBRARY == "eventlet": + return eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS + elif CONCURRENCY_LIBRARY == "gevent": + # matches what DEFAULT_MAX_SIMULTANEOUS_REQUESTS is for eventlet + return 1024 + else: + raise ValueError("Unsupported concurrency library") + + def get_green_pool_class(): if CONCURRENCY_LIBRARY == "eventlet": return eventlet.GreenPool @@ -173,3 +183,15 @@ def green_pool_wait_all(pool): return all(gl.ready() for gl in pool.greenlets) else: raise ValueError("Unsupported concurrency library") + +def listen_server(host, port): + if CONCURRENCY_LIBRARY == "eventlet": + return eventlet.listen((host, port)) + elif CONCURRENCY_LIBRARY == "gevent": + import socket + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind((host, port)) + return sock.listen(5) + else: + raise ValueError("Unsupported concurrency library") + diff --git a/st2common/st2common/util/monkey_patch.py b/st2common/st2common/util/monkey_patch.py index 2694d3d785..c852a48b2c 100644 --- a/st2common/st2common/util/monkey_patch.py +++ b/st2common/st2common/util/monkey_patch.py @@ -57,8 +57,11 @@ def monkey_patch(patch_thread=None): os=True, select=True, socket=True, thread=patch_thread, time=True ) elif concurrency_library == "gevent": - # TODO: support gevent.patch_all if .concurrency.CONCURRENCY_LIBRARY = "gevent" - raise NotImplementedError + # Match what eventlet was enabling, fallback on gevent defaults + import gevent + gevent.monkey.patch_all( + os=True, select=True, thread=True, time=True, socket=True + ) else: raise RuntimeError(f"Unsupported concurrency library {concurrency_library}") diff --git a/st2stream/st2stream/cmd/api.py b/st2stream/st2stream/cmd/api.py index 3de0c89f03..08caa0a2bd 100644 --- a/st2stream/st2stream/cmd/api.py +++ b/st2stream/st2stream/cmd/api.py @@ -21,6 +21,7 @@ import sys import eventlet + from oslo_config import cfg from eventlet import wsgi @@ -29,6 +30,7 @@ from st2common.service_setup import teardown as common_teardown from st2common.service_setup import deregister_service from st2common.stream.listener import get_listener_if_set +from st2common.util import concurrency from st2common.util.wsgi import shutdown_server_kill_pending_requests from st2stream.signal_handlers import register_stream_signal_handlers from st2stream import config @@ -40,13 +42,13 @@ __all__ = ["main"] -eventlet.monkey_patch( - os=True, - select=True, - socket=True, - thread=False if "--use-debugger" in sys.argv else True, - time=True, -) +#eventlet.monkey_patch( +# os=True, +# select=True, +# socket=True, +# thread=False if "--use-debugger" in sys.argv else True, +# time=True, +#) LOG = logging.getLogger(__name__) STREAM = "stream" @@ -83,9 +85,9 @@ def _run_server(): "(PID=%s) ST2 Stream API is serving on http://%s:%s.", os.getpid(), host, port ) - max_pool_size = eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS - worker_pool = eventlet.GreenPool(max_pool_size) - sock = eventlet.listen((host, port)) + max_pool_size = concurrency.get_default_green_pool_size() + worker_pool = concurrency.get_green_pool_class()(max_pool_size) + sock = concurrency.listen_server(host, port) def queue_shutdown(signal_number, stack_frame): deregister_service(STREAM) From b21d288ba23d7c10cf62d59992785a8a8e263a1e Mon Sep 17 00:00:00 2001 From: Carlos Date: Thu, 19 Feb 2026 21:53:54 +0100 Subject: [PATCH 2/5] Add gevent to pants requirements and regenerate lock file. --- lockfiles/st2.lock | 523 +++++++++++++++++++++++++++++++++-------- requirements-pants.txt | 3 +- 2 files changed, 422 insertions(+), 104 deletions(-) diff --git a/lockfiles/st2.lock b/lockfiles/st2.lock index 779589e997..427b424009 100644 --- a/lockfiles/st2.lock +++ b/lockfiles/st2.lock @@ -22,6 +22,7 @@ // "eventlet", // "flask", // "flex", +// "gevent", // "gitdb", // "gitpython", // "graphviz", @@ -133,13 +134,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "6162cb5683cb09923654fa9bdd3130c4be4bfda6ad8990971c9597ecd52965d2", - "url": "https://files.pythonhosted.org/packages/58/9f/d3c76f76c73fcc959d28e9def45b8b1cc3d7722660c5003b19c1022fd7f4/apscheduler-3.11.1-py3-none-any.whl" + "hash": "ce005177f741409db4e4dd40a7431b76feb856b9dd69d57e0da49d6715bfd26d", + "url": "https://files.pythonhosted.org/packages/9f/64/2e54428beba8d9992aa478bb8f6de9e4ecaa5f8f513bcfd567ed7fb0262d/apscheduler-3.11.2-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "0db77af6400c84d1747fe98a04b8b58f0080c77d11d338c4f507a9752880f221", - "url": "https://files.pythonhosted.org/packages/d0/81/192db4f8471de5bc1f0d098783decffb1e6e69c4f8b4bc6711094691950b/apscheduler-3.11.1.tar.gz" + "hash": "2a9966b052ec805f020c8c4c3ae6e6a06e24b1bf19f2e11d91d8cca0473eef41", + "url": "https://files.pythonhosted.org/packages/07/12/3e4389e5920b4c1763390c6d371162f3784f86f85cd6d6c1bfe68eef14e2/apscheduler-3.11.2.tar.gz" } ], "project_name": "apscheduler", @@ -155,6 +156,7 @@ "packaging; extra == \"doc\"", "protobuf<=3.21.0; extra == \"etcd\"", "pymongo>=3.0; extra == \"mongodb\"", + "pytest-timeout; extra == \"test\"", "pytest; extra == \"test\"", "pytz; extra == \"test\"", "redis>=3.0; extra == \"redis\"", @@ -168,7 +170,7 @@ "tzlocal>=3.0" ], "requires_python": ">=3.8", - "version": "3.11.1" + "version": "3.11.2" }, { "artifacts": [ @@ -542,19 +544,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", - "url": "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl" + "hash": "9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", + "url": "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", - "url": "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz" + "hash": "ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", + "url": "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz" } ], "project_name": "certifi", "requires_dists": [], "requires_python": ">=3.7", - "version": "2025.11.12" + "version": "2026.1.4" }, { "artifacts": [ @@ -1878,6 +1880,169 @@ "requires_python": ">=3.8", "version": "3.0.0" }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "7b00f8c9065de3ad226f7979154a7b27f3b9151c8055c162332369262fc025d8", + "url": "https://files.pythonhosted.org/packages/ae/15/c1cd1f2005f457028ecde345260fc4ab2197c6b660a8f3729784a6a903ca/gevent-24.2.1-pp310-pypy310_pp73-macosx_11_0_universal2.whl" + }, + { + "algorithm": "sha256", + "hash": "8f4b8e777d39013595a7740b4463e61b1cfe5f462f1b609b28fbc1e4c4ff01e5", + "url": "https://files.pythonhosted.org/packages/07/5a/a0b6c4cdd0917137c587edaba76b6c679181e10d25405247d2f5d8a2751d/gevent-24.2.1-cp38-cp38-macosx_11_0_universal2.whl" + }, + { + "algorithm": "sha256", + "hash": "cdf66977a976d6a3cfb006afdf825d1482f84f7b81179db33941f2fc9673bb1d", + "url": "https://files.pythonhosted.org/packages/15/12/7c91964af7112b3b435aa836401d8ca212ba9d43bcfea34c770b73515740/gevent-24.2.1-cp311-cp311-musllinux_1_1_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "6f947a9abc1a129858391b3d9334c45041c08a0f23d14333d5b844b6e5c17a07", + "url": "https://files.pythonhosted.org/packages/15/9e/e775a6b261bd871f37a2aae4c335d150f2c64c54c166e8dd8cf63210b445/gevent-24.2.1-cp310-cp310-macosx_11_0_universal2.whl" + }, + { + "algorithm": "sha256", + "hash": "ca80b121bbec76d7794fcb45e65a7eca660a76cc1a104ed439cdbd7df5f0b060", + "url": "https://files.pythonhosted.org/packages/1e/0f/66b517209682f7ec2863fd6ea13e26cc015d3c7e12c0acbd19d14cc67ac8/gevent-24.2.1-cp310-cp310-manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "141a2b24ad14f7b9576965c0c84927fc85f824a9bb19f6ec1e61e845d87c9cd8", + "url": "https://files.pythonhosted.org/packages/20/4d/0972d1ff47f118aeb32d0b33b50aed73583c31238dc063cb5ba230acbe38/gevent-24.2.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "432fc76f680acf7cf188c2ee0f5d3ab73b63c1f03114c7cd8a34cebbe5aa2056", + "url": "https://files.pythonhosted.org/packages/27/24/a3a7b713acfcf1177207f49ec25c665123f8972f42bee641bcc9f32961f4/gevent-24.2.1.tar.gz" + }, + { + "algorithm": "sha256", + "hash": "d7f87c2c02e03d99b95cfa6f7a776409083a9e4d468912e18c7680437b29222c", + "url": "https://files.pythonhosted.org/packages/40/9c/8880eef385b31f694222f5c94b2b487a8b37b99aceeed3e93cb0cb038511/gevent-24.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "f8bb35ce57a63c9a6896c71a285818a3922d8ca05d150fd1fe49a7f57287b836", + "url": "https://files.pythonhosted.org/packages/4a/db/64295bfd9a51874b715e82ba5ab971f2c298cf283297e4cf5bec37db17d9/gevent-24.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "f5e8e8d60e18d5f7fd49983f0c4696deeddaf6e608fbab33397671e2fcc6cc91", + "url": "https://files.pythonhosted.org/packages/58/b8/aaf9ff71ba9a7012e04400726b0e0e6986460030dfae3168482069422305/gevent-24.2.1-cp311-cp311-manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "90cbac1ec05b305a1b90ede61ef73126afdeb5a804ae04480d6da12c56378df1", + "url": "https://files.pythonhosted.org/packages/5f/67/c2e3b6f45f77019a9bec6e594f1abede96fd2cd9292024cc6a334648b5e0/gevent-24.2.1-cp39-cp39-musllinux_1_1_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "a7ceb59986456ce851160867ce4929edaffbd2f069ae25717150199f8e1548b8", + "url": "https://files.pythonhosted.org/packages/63/11/9f67d737a64217649460b2654b595afd9a2565d20688d92c18b17e522ec5/gevent-24.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "03aa5879acd6b7076f6a2a307410fb1e0d288b84b03cdfd8c74db8b4bc882fc5", + "url": "https://files.pythonhosted.org/packages/64/34/e561fb53ec80e81a83b76667c004c838a292dde8adf80ff289558b4a4df8/gevent-24.2.1-cp311-cp311-macosx_11_0_universal2.whl" + }, + { + "algorithm": "sha256", + "hash": "b9913c45d1be52d7a5db0c63977eebb51f68a2d5e6fd922d1d9b5e5fd758cc98", + "url": "https://files.pythonhosted.org/packages/6b/ee/883de5d784d5ffbb349549be82b805d668a841c2bb2b17bb294af2740d16/gevent-24.2.1-cp310-cp310-musllinux_1_1_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "14532a67f7cb29fb055a0e9b39f16b88ed22c66b96641df8c04bdc38c26b9ea5", + "url": "https://files.pythonhosted.org/packages/6b/f5/14d4085bb7774ed6cb84d9fd2360a9b3a99a502183b4979c8cad253dfba2/gevent-24.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl" + }, + { + "algorithm": "sha256", + "hash": "fbfdce91239fe306772faab57597186710d5699213f4df099d1612da7320d682", + "url": "https://files.pythonhosted.org/packages/74/ee/6febc62ddd399b0f060785bea8ae3c994ce47dfe6ec46ece3b1a90cc496b/gevent-24.2.1-cp311-cp311-musllinux_1_1_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "2ae3a25ecce0a5b0cd0808ab716bfca180230112bb4bc89b46ae0061d62d4afe", + "url": "https://files.pythonhosted.org/packages/78/23/328809bc89c21669434fddaa863c33008486a423eb7ea049b2bf82ae154b/gevent-24.2.1-cp39-cp39-macosx_11_0_universal2.whl" + }, + { + "algorithm": "sha256", + "hash": "2955eea9c44c842c626feebf4459c42ce168685aa99594e049d03bedf53c2800", + "url": "https://files.pythonhosted.org/packages/7a/1c/528238b5460dfcd16a76f4ab7837d6fef899fbf0666c248891efb21b0829/gevent-24.2.1-cp38-cp38-musllinux_1_1_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "918cdf8751b24986f915d743225ad6b702f83e1106e08a63b736e3a4c6ead789", + "url": "https://files.pythonhosted.org/packages/7c/27/a0eee37ba204411c48744b6cfbb79afd01e50185c3cd91421948f1cc40f1/gevent-24.2.1-cp310-cp310-musllinux_1_1_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "2e9ac06f225b696cdedbb22f9e805e2dd87bf82e8fa5e17756f94e88a9d37cf7", + "url": "https://files.pythonhosted.org/packages/7f/1f/b9b5b38c65e8a69fedb11b43ba3c824b164dde21ffa19491e1e866876c8b/gevent-24.2.1-cp39-cp39-manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "dd23df885318391856415e20acfd51a985cba6919f0be78ed89f5db9ff3a31cb", + "url": "https://files.pythonhosted.org/packages/8c/ab/348bc172ef72f82c5684764887d4a5751200dad2ce772b164e120dd489ee/gevent-24.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "968581d1717bbcf170758580f5f97a2925854943c45a19be4d47299507db2eb7", + "url": "https://files.pythonhosted.org/packages/9c/0e/bf924a9998137d51e8ba84bd600ff5de17e405284811b26307748c0e0f9b/gevent-24.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl" + }, + { + "algorithm": "sha256", + "hash": "7899a38d0ae7e817e99adb217f586d0a4620e315e4de577444ebeeed2c5729be", + "url": "https://files.pythonhosted.org/packages/a1/bc/0f776a3f5a3c57e3f6bbe8abc3d39cc591f58aa03808b50af4f73ae4b238/gevent-24.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "5a1df555431f5cd5cc189a6ee3544d24f8c52f2529134685f1e878c4972ab026", + "url": "https://files.pythonhosted.org/packages/ca/0d/28048ce07ffb9cabf974583092bcb6008b8c55f880609f1515a085adb1f9/gevent-24.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" + }, + { + "algorithm": "sha256", + "hash": "9202f22ef811053077d01f43cc02b4aaf4472792f9fd0f5081b0b05c926cca19", + "url": "https://files.pythonhosted.org/packages/e7/26/f7349b02cb06c87b2e5eb4547a33b3c5171076460bc45e18ec723d84320d/gevent-24.2.1-cp38-cp38-manylinux_2_28_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "bde283313daf0b34a8d1bab30325f5cb0f4e11b5869dbe5bc61f8fe09a8f66f3", + "url": "https://files.pythonhosted.org/packages/eb/6b/396ef229ee05286b957915cb3d96c8ff28793b2f21508ee4b6e51e207bbc/gevent-24.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + } + ], + "project_name": "gevent", + "requires_dists": [ + "cffi>=1.12.2; platform_python_implementation == \"CPython\" and extra == \"recommended\"", + "cffi>=1.12.2; platform_python_implementation == \"CPython\" and extra == \"test\"", + "cffi>=1.12.2; platform_python_implementation == \"CPython\" and sys_platform == \"win32\"", + "coverage>=5.0; sys_platform != \"win32\" and extra == \"test\"", + "dnspython<2.0,>=1.16.0; python_version < \"3.10\" and extra == \"dnspython\"", + "dnspython<2.0,>=1.16.0; python_version < \"3.10\" and extra == \"recommended\"", + "dnspython<2.0,>=1.16.0; python_version < \"3.10\" and extra == \"test\"", + "furo; extra == \"docs\"", + "greenlet>=2.0.0; platform_python_implementation == \"CPython\" and python_version < \"3.11\"", + "greenlet>=3.0rc3; platform_python_implementation == \"CPython\" and python_version >= \"3.11\"", + "idna; python_version < \"3.10\" and extra == \"dnspython\"", + "idna; python_version < \"3.10\" and extra == \"recommended\"", + "idna; python_version < \"3.10\" and extra == \"test\"", + "objgraph; extra == \"test\"", + "psutil>=5.7.0; (sys_platform != \"win32\" or platform_python_implementation == \"CPython\") and extra == \"monitor\"", + "psutil>=5.7.0; (sys_platform != \"win32\" or platform_python_implementation == \"CPython\") and extra == \"recommended\"", + "psutil>=5.7.0; (sys_platform != \"win32\" or platform_python_implementation == \"CPython\") and extra == \"test\"", + "repoze.sphinx.autointerface; extra == \"docs\"", + "requests; extra == \"test\"", + "sphinx; extra == \"docs\"", + "sphinxcontrib-programoutput; extra == \"docs\"", + "zope.event", + "zope.interface", + "zope.schema; extra == \"docs\"" + ], + "requires_python": ">=3.8", + "version": "24.2.1" + }, { "artifacts": [ { @@ -1902,13 +2067,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", - "url": "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl" + "hash": "79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", + "url": "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c", - "url": "https://files.pythonhosted.org/packages/9a/c8/dd58967d119baab745caec2f9d853297cec1989ec1d63f677d3880632b88/gitpython-3.1.45.tar.gz" + "hash": "400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", + "url": "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz" } ], "project_name": "gitpython", @@ -1917,7 +2082,7 @@ "ddt!=1.4.3,>=1.1.1; extra == \"test\"", "gitdb<5,>=4.0.1", "mock; python_version < \"3.8\" and extra == \"test\"", - "mypy; extra == \"test\"", + "mypy==1.18.2; python_version >= \"3.9\" and extra == \"test\"", "pre-commit; extra == \"test\"", "pytest-cov; extra == \"test\"", "pytest-instafail; extra == \"test\"", @@ -1931,7 +2096,7 @@ "typing-extensions>=3.10.0.2; python_version < \"3.10\"" ], "requires_python": ">=3.7", - "version": "3.1.45" + "version": "3.1.46" }, { "artifacts": [ @@ -2176,39 +2341,39 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "b9cd78abea9b4e43a7714c6e0f8b6b8561a6fc1e95d5dbd367f5bf0ef35f5d24", - "url": "https://files.pythonhosted.org/packages/8c/a2/0d269db0f6163be503775dc8b6a6fa15820cc9fdc866f6ba608d86b721f2/httplib2-0.31.0-py3-none-any.whl" + "hash": "dbf0c2fa3862acf3c55c078ea9c0bc4481d7dc5117cae71be9514912cf9f8349", + "url": "https://files.pythonhosted.org/packages/2f/90/fd509079dfcab01102c0fdd87f3a9506894bc70afcf9e9785ef6b2b3aff6/httplib2-0.31.2-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "ac7ab497c50975147d4f7b1ade44becc7df2f8954d42b38b3d69c515f531135c", - "url": "https://files.pythonhosted.org/packages/52/77/6653db69c1f7ecfe5e3f9726fdadc981794656fcd7d98c4209fecfea9993/httplib2-0.31.0.tar.gz" + "hash": "385e0869d7397484f4eab426197a4c020b606edd43372492337c0b4010ae5d24", + "url": "https://files.pythonhosted.org/packages/c1/1f/e86365613582c027dda5ddb64e1010e57a3d53e99ab8a72093fa13d565ec/httplib2-0.31.2.tar.gz" } ], "project_name": "httplib2", "requires_dists": [ - "pyparsing<4,>=3.0.4" + "pyparsing<4,>=3.1" ], "requires_python": ">=3.6", - "version": "0.31.0" + "version": "0.31.2" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "f05d1b3623223dd1c70f7848da7d699de3d9a2550b902a8234d9026292fb5762", - "url": "https://files.pythonhosted.org/packages/7c/2a/b3178baa75a3ec75a33588252296c82a1332d2b83cd01061539b74bde9dd/icdiff-2.0.7-py3-none-any.whl" + "hash": "fd8ce592d94261c435e2a410f668a41ec3be4527878f8df01100797021d8edb0", + "url": "https://files.pythonhosted.org/packages/85/4b/bb94514476624bfff977599e5ef3ac9aea603abb693639ed305b22ed1b35/icdiff-2.0.10-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "f79a318891adbf59a45e3a7694f5e1f18c5407065264637072ac8363b759866f", - "url": "https://files.pythonhosted.org/packages/fa/e4/43341832be5f2bcae71eb3ef08a07aaef9b74f74fe0b3675f62bd12057fe/icdiff-2.0.7.tar.gz" + "hash": "75a3de5c9af35ab45fb0504df59770c514a12c0d2b2c99e5f9c5c2429957e133", + "url": "https://files.pythonhosted.org/packages/5b/6d/41c8ff13b67c30ceb9325398ff6bb9fc4b77208c6c1d79db8d5913840bc6/icdiff-2.0.10.tar.gz" } ], "project_name": "icdiff", "requires_dists": [], "requires_python": null, - "version": "2.0.7" + "version": "2.0.10" }, { "artifacts": [ @@ -3455,19 +3620,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", - "url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl" + "hash": "b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", + "url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", - "url": "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz" + "hash": "00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", + "url": "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz" } ], "project_name": "packaging", "requires_dists": [], "requires_python": ">=3.8", - "version": "25.0" + "version": "26.0" }, { "artifacts": [ @@ -3729,28 +3894,38 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "56d974e02ca2c8eb4812c3f76c30e28836fffc311d55d979f1465c1feeb2b68b", - "url": "https://files.pythonhosted.org/packages/e0/95/992c8816a74016eb095e73585d747e0a8ea21a061ed3689474fabb29a395/psutil-7.1.3-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", + "url": "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", + "url": "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", + "url": "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "bc31fa00f1fbc3c3802141eede66f3a2d51d89716a194bf2cd6fc68310a19880", - "url": "https://files.pythonhosted.org/packages/68/3a/9f93cff5c025029a36d9a92fef47220ab4692ee7f2be0fba9f92813d0cb8/psutil-7.1.3-cp36-abi3-macosx_11_0_arm64.whl" + "hash": "fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", + "url": "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "3bb428f9f05c1225a558f53e30ccbad9930b11c3fc206836242de1091d3e7dd3", - "url": "https://files.pythonhosted.org/packages/ce/b1/5f49af514f76431ba4eea935b8ad3725cdeb397e9245ab919dbc1d1dc20f/psutil-7.1.3-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl" + "hash": "0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", + "url": "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz" }, { "algorithm": "sha256", - "hash": "6c86281738d77335af7aec228328e944b30930899ea760ecf33a4dba66be5e74", - "url": "https://files.pythonhosted.org/packages/e1/88/bdd0a41e5857d5d703287598cbf08dad90aed56774ea52ae071bae9071b6/psutil-7.1.3.tar.gz" + "hash": "076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", + "url": "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "2bdbcd0e58ca14996a42adf3621a6244f1bb2e2e528886959c72cf1e326677ab", - "url": "https://files.pythonhosted.org/packages/ef/94/46b9154a800253e7ecff5aaacdf8ebf43db99de4a2dfa18575b02548654e/psutil-7.1.3-cp36-abi3-macosx_10_9_x86_64.whl" + "hash": "ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", + "url": "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl" } ], "project_name": "psutil", @@ -3761,21 +3936,21 @@ "colorama; os_name == \"nt\" and extra == \"dev\"", "coverage; extra == \"dev\"", "packaging; extra == \"dev\"", + "psleak; extra == \"dev\"", + "psleak; extra == \"test\"", "pylint; extra == \"dev\"", "pyperf; extra == \"dev\"", "pypinfo; extra == \"dev\"", - "pyreadline; os_name == \"nt\" and extra == \"dev\"", + "pyreadline3; os_name == \"nt\" and extra == \"dev\"", "pytest-cov; extra == \"dev\"", "pytest-instafail; extra == \"dev\"", "pytest-instafail; extra == \"test\"", - "pytest-subtests; extra == \"dev\"", - "pytest-subtests; extra == \"test\"", "pytest-xdist; extra == \"dev\"", "pytest-xdist; extra == \"test\"", "pytest; extra == \"dev\"", "pytest; extra == \"test\"", - "pywin32; (os_name == \"nt\" and platform_python_implementation != \"PyPy\") and extra == \"dev\"", - "pywin32; (os_name == \"nt\" and platform_python_implementation != \"PyPy\") and extra == \"test\"", + "pywin32; (os_name == \"nt\" and implementation_name != \"pypy\") and extra == \"dev\"", + "pywin32; (os_name == \"nt\" and implementation_name != \"pypy\") and extra == \"test\"", "requests; extra == \"dev\"", "rstcheck; extra == \"dev\"", "ruff; extra == \"dev\"", @@ -3788,14 +3963,14 @@ "validate-pyproject[all]; extra == \"dev\"", "virtualenv; extra == \"dev\"", "vulture; extra == \"dev\"", - "wheel; (os_name == \"nt\" and platform_python_implementation != \"PyPy\") and extra == \"dev\"", - "wheel; (os_name == \"nt\" and platform_python_implementation != \"PyPy\") and extra == \"test\"", + "wheel; (os_name == \"nt\" and implementation_name != \"pypy\") and extra == \"dev\"", + "wheel; (os_name == \"nt\" and implementation_name != \"pypy\") and extra == \"test\"", "wheel; extra == \"dev\"", - "wmi; (os_name == \"nt\" and platform_python_implementation != \"PyPy\") and extra == \"dev\"", - "wmi; (os_name == \"nt\" and platform_python_implementation != \"PyPy\") and extra == \"test\"" + "wmi; (os_name == \"nt\" and implementation_name != \"pypy\") and extra == \"dev\"", + "wmi; (os_name == \"nt\" and implementation_name != \"pypy\") and extra == \"test\"" ], "requires_python": ">=3.6", - "version": "7.1.3" + "version": "7.2.2" }, { "artifacts": [ @@ -3837,19 +4012,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", - "url": "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl" + "hash": "1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf", + "url": "https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", - "url": "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz" + "hash": "9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b", + "url": "https://files.pythonhosted.org/packages/fe/b6/6e630dff89739fcd427e3f72b3d905ce0acb85a45d4ec3e2678718a3487f/pyasn1-0.6.2.tar.gz" } ], "project_name": "pyasn1", "requires_dists": [], "requires_python": ">=3.8", - "version": "0.6.1" + "version": "0.6.2" }, { "artifacts": [ @@ -5327,13 +5502,13 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "90ab613b6583fc02d5369cbca13ea26ea0e182d1df2d943ee9cbe81d4c61add9", - "url": "https://files.pythonhosted.org/packages/15/65/3f0dba35760d902849d39d38c0a72767794b1963227b69a587f8a336d08c/setuptools-75.3.2-py3-none-any.whl" + "hash": "2dd50a7f42dddfa1d02a36f275dbe716f38ed250224f609d35fb60a09593d93e", + "url": "https://files.pythonhosted.org/packages/cd/b1/961ba076c7d3732e3a97e6681c55ef647afb795fe8bfcd27becec8a762ce/setuptools-75.3.4-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "3c1383e1038b68556a382c1e8ded8887cd20141b0eb5708a6c8d277de49364f5", - "url": "https://files.pythonhosted.org/packages/5c/01/771ea46cce201dd42cff043a5eea929d1c030fb3d1c2ee2729d02ca7814c/setuptools-75.3.2.tar.gz" + "hash": "b4ea3f76e1633c4d2d422a5d68ab35fd35402ad71e6acaa5d7e5956eb47e8887", + "url": "https://files.pythonhosted.org/packages/0e/93/d2622cbf262418995140dfc1ddb890badd6322893fa122302577c82b9617/setuptools-75.3.4.tar.gz" } ], "project_name": "setuptools", @@ -5395,7 +5570,7 @@ "wheel>=0.44.0; extra == \"test\"" ], "requires_python": ">=3.8", - "version": "75.3.2" + "version": "75.3.4" }, { "artifacts": [ @@ -5693,19 +5868,14 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "4ecca6dc0b9f963f8384e9d7fd529bf93dd7d708144c4fb5da0e0a1a926fee83", - "url": "https://files.pythonhosted.org/packages/49/58/97655efdfeb5b4eeab85b1fc5d3fa1023661246c2ab2a26ea8e47402d4f2/sseclient_py-1.8.0-py2.py3-none-any.whl" - }, - { - "algorithm": "sha256", - "hash": "c547c5c1a7633230a38dc599a21a2dc638f9b5c297286b48b46b935c71fac3e8", - "url": "https://files.pythonhosted.org/packages/e8/ed/3df5ab8bb0c12f86c28d0cadb11ed1de44a92ed35ce7ff4fd5518a809325/sseclient-py-1.8.0.tar.gz" + "hash": "340062b1587fc2880892811e2ab5b176d98ef3eee98b3672ff3a3ba1e8ed0f6f", + "url": "https://files.pythonhosted.org/packages/4d/2e/59920f7d66b7f9932a3d83dd0ec53fab001be1e058bf582606fe414a5198/sseclient_py-1.9.0-py3-none-any.whl" } ], "project_name": "sseclient-py", "requires_dists": [], - "requires_python": null, - "version": "1.8.0" + "requires_python": ">=3.7", + "version": "1.9.0" }, { "artifacts": [ @@ -5744,7 +5914,7 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "ab97c2a3d4a0a520d7fbdaf1dee5d670de9e51c157d11ed45322c84d6daadc50", + "hash": "69fe7f8c09c828d4a351f74be08834cf3e7164591ed2e40dd5c3db6ab127c2e4", "url": "git+https://github.com/StackStorm/st2-auth-ldap.git@master" } ], @@ -5754,20 +5924,20 @@ "python-ldap<3.5.0,>=3.4.0" ], "requires_python": ">=3.8", - "version": "3.9.dev0" + "version": "3.10.dev0" }, { "artifacts": [ { "algorithm": "sha256", - "hash": "f445faec6e5f55437f379be08dd78aa2f1181ed9dbd04fe19bddfb6f4c2fe911", + "hash": "ce1bcd8b63fb864688f94f12b20299fdf9ba856b23740bc5954224bca39064a6", "url": "git+https://github.com/StackStorm/st2-rbac-backend.git@master" } ], "project_name": "st2-rbac-backend", "requires_dists": [], "requires_python": null, - "version": "3.9.dev0" + "version": "3.10.dev0" }, { "artifacts": [ @@ -5850,49 +6020,49 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", - "url": "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl" + "hash": "1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", + "url": "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", - "url": "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + "hash": "b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", + "url": "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl" }, { "algorithm": "sha256", - "hash": "64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", - "url": "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz" + "hash": "5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", + "url": "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl" }, { "algorithm": "sha256", - "hash": "0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", - "url": "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl" + "hash": "aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", + "url": "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz" }, { "algorithm": "sha256", - "hash": "883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", - "url": "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl" + "hash": "1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", + "url": "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl" }, { "algorithm": "sha256", - "hash": "a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", - "url": "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + "hash": "133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", + "url": "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl" }, { "algorithm": "sha256", - "hash": "88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", - "url": "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl" + "hash": "5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", + "url": "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" }, { "algorithm": "sha256", - "hash": "74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", - "url": "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl" + "hash": "551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", + "url": "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" } ], "project_name": "tomli", "requires_dists": [], "requires_python": ">=3.8", - "version": "2.3.0" + "version": "2.4.0" }, { "artifacts": [ @@ -5960,19 +6130,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", - "url": "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl" + "hash": "06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", + "url": "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", - "url": "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz" + "hash": "de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", + "url": "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz" } ], "project_name": "tzdata", "requires_dists": [], "requires_python": ">=2", - "version": "2025.2" + "version": "2025.3" }, { "artifacts": [ @@ -6401,19 +6571,19 @@ "artifacts": [ { "algorithm": "sha256", - "hash": "a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", - "url": "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl" + "hash": "1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", + "url": "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl" }, { "algorithm": "sha256", - "hash": "4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", - "url": "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz" + "hash": "cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", + "url": "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz" } ], "project_name": "wcwidth", "requires_dists": [], - "requires_python": ">=3.6", - "version": "0.2.14" + "requires_python": ">=3.8", + "version": "0.6.0" }, { "artifacts": [ @@ -6822,6 +6992,152 @@ "requires_python": ">=3.8", "version": "3.20.2" }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "2832e95014f4db26c47a13fdaef84cef2f4df37e66b59d8f1f4a8f319a632c26", + "url": "https://files.pythonhosted.org/packages/fe/42/f8dbc2b9ad59e927940325a22d6d3931d630c3644dae7e2369ef5d9ba230/zope.event-5.0-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "bac440d8d9891b4068e2b5a2c5e2c9765a9df762944bda6955f96bb9b91e67cd", + "url": "https://files.pythonhosted.org/packages/46/c2/427f1867bb96555d1d34342f1dd97f8c420966ab564d58d18469a1db8736/zope.event-5.0.tar.gz" + } + ], + "project_name": "zope-event", + "requires_dists": [ + "Sphinx; extra == \"docs\"", + "setuptools", + "zope.testrunner; extra == \"test\"" + ], + "requires_python": ">=3.7", + "version": "5.0" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "2ad9913fd858274db8dd867012ebe544ef18d218f6f7d1e3c3e6d98000f14b75", + "url": "https://files.pythonhosted.org/packages/88/d4/4ba1569b856870527cec4bf22b91fe704b81a3c1a451b2ccf234e9e0666f/zope.interface-7.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "550f1c6588ecc368c9ce13c44a49b8d6b6f3ca7588873c679bd8fd88a1b557b6", + "url": "https://files.pythonhosted.org/packages/28/ea/fdd9813c1eafd333ad92464d57a4e3a82b37ae57c19497bcffa42df673e4/zope.interface-7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "52e446f9955195440e787596dccd1411f543743c359eeb26e9b2c02b077b0519", + "url": "https://files.pythonhosted.org/packages/2a/dd/fcd313ee216ad0739ae00e6126bc22a0af62a74f76a9ca668d16cd276222/zope.interface-7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "8b49f1a3d1ee4cdaf5b32d2e738362c7f5e40ac8b46dd7d1a65e82a4872728fe", + "url": "https://files.pythonhosted.org/packages/30/93/9210e7606be57a2dfc6277ac97dcc864fd8d39f142ca194fdc186d596fda/zope.interface-7.2.tar.gz" + }, + { + "algorithm": "sha256", + "hash": "72cd1790b48c16db85d51fbbd12d20949d7339ad84fd971427cf00d990c1f137", + "url": "https://files.pythonhosted.org/packages/36/22/b1abd91854c1be03f5542fe092e6a745096d2eca7704d69432e119100583/zope.interface-7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "0ef9e2f865721553c6f22a9ff97da0f0216c074bd02b25cf0d3af60ea4d6931d", + "url": "https://files.pythonhosted.org/packages/3b/d3/0000a4d497ef9fbf4f66bb6828b8d0a235e690d57c333be877bec763722f/zope.interface-7.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "27f926f0dcb058211a3bb3e0e501c69759613b17a553788b2caeb991bed3b61d", + "url": "https://files.pythonhosted.org/packages/3e/e5/0b359e99084f033d413419eff23ee9c2bd33bca2ca9f4e83d11856f22d10/zope.interface-7.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "033b3923b63474800b04cba480b70f6e6243a62208071fc148354f3f89cc01b7", + "url": "https://files.pythonhosted.org/packages/49/b4/451f19448772b4a1159519033a5f72672221e623b0a1bd2b896b653943d8/zope.interface-7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "05b910a5afe03256b58ab2ba6288960a2892dfeef01336dc4be6f1b9ed02ab0a", + "url": "https://files.pythonhosted.org/packages/52/db/7e5f4226bef540f6d55acfd95cd105782bc6ee044d9b5587ce2c95558a5e/zope.interface-7.2-cp310-cp310-macosx_11_0_arm64.whl" + }, + { + "algorithm": "sha256", + "hash": "a102424e28c6b47c67923a1f337ede4a4c2bba3965b01cf707978a801fc7442c", + "url": "https://files.pythonhosted.org/packages/65/94/5aa4461c10718062c8f8711161faf3249d6d3679c24a0b81dd6fc8ba1dd3/zope.interface-7.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "ce290e62229964715f1011c3dbeab7a4a1e4971fd6f31324c4519464473ef9f2", + "url": "https://files.pythonhosted.org/packages/76/71/e6177f390e8daa7e75378505c5ab974e0bf59c1d3b19155638c7afbf4b2d/zope.interface-7.2-cp310-cp310-macosx_10_9_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "baf95683cde5bc7d0e12d8e7588a3eb754d7c4fa714548adcd96bdf90169f021", + "url": "https://files.pythonhosted.org/packages/8a/cd/f1e8303b81151cd6ba6e229db5fe601f9867a7b29f24a95eeba255970099/zope.interface-7.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "7bd449c306ba006c65799ea7912adbbfed071089461a19091a228998b82b1fdb", + "url": "https://files.pythonhosted.org/packages/8c/2c/1f49dc8b4843c4f0848d8e43191aed312bad946a1563d1bf9e46cf2816ee/zope.interface-7.2-cp39-cp39-macosx_10_9_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "1909f52a00c8c3dcab6c4fad5d13de2285a4b3c7be063b239b8dc15ddfb73bd2", + "url": "https://files.pythonhosted.org/packages/98/7d/2e8daf0abea7798d16a58f2f3a2bf7588872eee54ac119f99393fdd47b65/zope.interface-7.2-cp311-cp311-macosx_10_9_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "224b7b0314f919e751f2bca17d15aad00ddbb1eadf1cb0190fa8175edb7ede62", + "url": "https://files.pythonhosted.org/packages/9e/dd/5505c6fa2dd3a6b76176c07bc85ad0c24f218a3e7c929272384a5eb5f18a/zope.interface-7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "25e6a61dcb184453bb00eafa733169ab6d903e46f5c2ace4ad275386f9ab327a", + "url": "https://files.pythonhosted.org/packages/9f/aa/1a28c02815fe1ca282b54f6705b9ddba20328fabdc37b8cf73fc06b172f0/zope.interface-7.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "80ecf2451596f19fd607bb09953f426588fc1e79e93f5968ecf3367550396b22", + "url": "https://files.pythonhosted.org/packages/a0/2a/0c03c7170fe61d0d371e4c7ea5b62b8cb79b095b3d630ca16719bf8b7b18/zope.interface-7.2-cp311-cp311-macosx_11_0_arm64.whl" + }, + { + "algorithm": "sha256", + "hash": "d3a8ffec2a50d8ec470143ea3d15c0c52d73df882eef92de7537e8ce13475e8a", + "url": "https://files.pythonhosted.org/packages/e6/0f/4e296d4b36ceb5464b671443ac4084d586d47698610025c4731ff2d30eae/zope.interface-7.2-cp38-cp38-macosx_10_9_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "a19a6cc9c6ce4b1e7e3d319a473cf0ee989cbbe2b39201d7c19e214d2dfb80c7", + "url": "https://files.pythonhosted.org/packages/ed/7d/83ddbfc8424c69579a90fc8edc2b797223da2a8083a94d8dfa0e374c5ed4/zope.interface-7.2-cp39-cp39-macosx_11_0_arm64.whl" + }, + { + "algorithm": "sha256", + "hash": "31d06db13a30303c08d61d5fb32154be51dfcbdb8438d2374ae27b4e069aac40", + "url": "https://files.pythonhosted.org/packages/f5/8c/49548aaa4f691615d703b5bee88ea67f68eac8f94c9fb6f1b2f4ae631354/zope.interface-7.2-cp38-cp38-macosx_11_0_arm64.whl" + }, + { + "algorithm": "sha256", + "hash": "e204937f67b28d2dca73ca936d3039a144a081fc47a07598d44854ea2a106239", + "url": "https://files.pythonhosted.org/packages/fe/f9/5a66f98f8c21d644d94f95b9484564f76e175034de3a57a45ba72238ce10/zope.interface-7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + } + ], + "project_name": "zope-interface", + "requires_dists": [ + "Sphinx; extra == \"docs\"", + "coverage[toml]; extra == \"test\"", + "coverage[toml]; extra == \"testing\"", + "furo; extra == \"docs\"", + "repoze.sphinx.autointerface; extra == \"docs\"", + "setuptools", + "zope.event; extra == \"test\"", + "zope.event; extra == \"testing\"", + "zope.testing; extra == \"test\"", + "zope.testing; extra == \"testing\"" + ], + "requires_python": ">=3.8", + "version": "7.2" + }, { "artifacts": [ { @@ -7143,6 +7459,7 @@ "eventlet", "flask", "flex", + "gevent", "gitdb", "gitpython", "graphviz", diff --git a/requirements-pants.txt b/requirements-pants.txt index 87f4bebdb4..6c806d754a 100644 --- a/requirements-pants.txt +++ b/requirements-pants.txt @@ -18,7 +18,8 @@ flex # gitpython & gitdb are used for pack management gitdb gitpython -# st2common/tests/integration/test_util_green.py requires greenlet (as does eventlet) +# st2common/tests/integration/test_util_green.py requires greenlet (as does eventlet and gevent) +gevent greenlet gunicorn jinja2 From 765f7ee3f3fd0144f8973e28959af2765cb6df26 Mon Sep 17 00:00:00 2001 From: Carlos Date: Thu, 19 Feb 2026 23:17:38 +0100 Subject: [PATCH 3/5] Move explicit eventlet calls behind concurrency module in auth. --- st2auth/st2auth/cmd/api.py | 9 +++--- st2common/st2common/util/concurrency.py | 43 +++++++++++++++++++------ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/st2auth/st2auth/cmd/api.py b/st2auth/st2auth/cmd/api.py index e817765d97..7a379814e6 100644 --- a/st2auth/st2auth/cmd/api.py +++ b/st2auth/st2auth/cmd/api.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,12 +17,11 @@ monkey_patch() -import eventlet +from st2common.util import concurrency import os import sys from oslo_config import cfg -from eventlet import wsgi from st2common import log as logging from st2common.service_setup import setup as common_setup @@ -81,7 +80,7 @@ def _run_server(): if use_ssl and not os.path.isfile(key_file_path): raise ValueError('Private key file "%s" doesn\'t exist' % (key_file_path)) - socket = eventlet.listen((host, port)) + socket = concurrency.listen(host, port) if use_ssl: socket = eventlet.wrap_ssl( @@ -96,7 +95,7 @@ def _run_server(): host, port, ) - + wsgi = concurrency.get_wsgi_module() wsgi.server(socket, app.setup_app(), log=LOG, log_output=False) return 0 diff --git a/st2common/st2common/util/concurrency.py b/st2common/st2common/util/concurrency.py index f064be4292..00b3e89061 100644 --- a/st2common/st2common/util/concurrency.py +++ b/st2common/st2common/util/concurrency.py @@ -73,6 +73,21 @@ def get_subprocess_module(): from gevent import subprocess # pylint: disable=import-error return subprocess + else: + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") + + +def get_wsgi_module(): + if CONCURRENCY_LIBRARY == "eventlet": + from eventlet import wsgi + + return wsgi + elif CONCURRENCY_LIBRARY == "gevent": + from gevent import pywsgi + + return pywsgi + else: + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def subprocess_popen(*args, **kwargs): @@ -84,6 +99,8 @@ def subprocess_popen(*args, **kwargs): from gevent import subprocess # pylint: disable=import-error return subprocess.Popen(*args, **kwargs) + else: + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def spawn(func, *args, **kwargs): @@ -92,7 +109,7 @@ def spawn(func, *args, **kwargs): elif CONCURRENCY_LIBRARY == "gevent": return gevent.spawn(func, *args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def wait(green_thread, *args, **kwargs): @@ -101,7 +118,7 @@ def wait(green_thread, *args, **kwargs): elif CONCURRENCY_LIBRARY == "gevent": return green_thread.join(*args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def cancel(green_thread, *args, **kwargs): @@ -110,7 +127,7 @@ def cancel(green_thread, *args, **kwargs): elif CONCURRENCY_LIBRARY == "gevent": return green_thread.kill(*args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def kill(green_thread, *args, **kwargs): @@ -119,7 +136,16 @@ def kill(green_thread, *args, **kwargs): elif CONCURRENCY_LIBRARY == "gevent": return green_thread.kill(*args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") + + +def listen(host, port): + if CONCURRENCY_LIBRARY == "eventlet": + return eventlet.listen((host, port)) + elif CONCURRENCY_LIBRARY == "gevent": + raise NotImplementedError + else: + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def sleep(*args, **kwargs): @@ -128,7 +154,7 @@ def sleep(*args, **kwargs): elif CONCURRENCY_LIBRARY == "gevent": return gevent.sleep(*args, **kwargs) else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def get_greenlet_exit_exception_class(): @@ -137,7 +163,7 @@ def get_greenlet_exit_exception_class(): elif CONCURRENCY_LIBRARY == "gevent": return gevent.GreenletExit else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def get_default_green_pool_size(): @@ -156,7 +182,7 @@ def get_green_pool_class(): elif CONCURRENCY_LIBRARY == "gevent": return gevent.pool.Pool else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def is_green_pool_free(pool): @@ -168,7 +194,7 @@ def is_green_pool_free(pool): elif CONCURRENCY_LIBRARY == "gevent": return not pool.full() else: - raise ValueError("Unsupported concurrency library") + raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") def green_pool_wait_all(pool): @@ -194,4 +220,3 @@ def listen_server(host, port): return sock.listen(5) else: raise ValueError("Unsupported concurrency library") - From a527451356523f0814c1b0d712d8c5be6f7a8712 Mon Sep 17 00:00:00 2001 From: Carlos Date: Sun, 1 Mar 2026 16:04:25 +0100 Subject: [PATCH 4/5] Move blocking detection to concurrency module + black format --- st2common/st2common/service_setup.py | 33 +++++++++---------------- st2common/st2common/util/concurrency.py | 30 +++++++++++++++++++--- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/st2common/st2common/service_setup.py b/st2common/st2common/service_setup.py index 9e8ae7e07f..3e91ca7aee 100644 --- a/st2common/st2common/service_setup.py +++ b/st2common/st2common/service_setup.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,7 @@ import logging as stdlib_logging import six -import eventlet.debug + from oslo_config import cfg from tooz.coordination import GroupAlreadyExist from tooz.coordination import GroupNotCreated @@ -38,6 +38,7 @@ from st2common.transport.bootstrap_utils import register_kombu_serializers from st2common.bootstrap import runnersregistrar from st2common.signal_handlers import register_common_signal_handlers +from st2common.util.concurrency import blocking_detection from st2common.util.debugging import enable_debugging from st2common.models.utils.profiling import enable_profiling from st2common import triggers @@ -182,8 +183,7 @@ def setup( or encoding.lower() not in VALID_UTF8_ENCODINGS ): LOG.warning( - NON_UTF8_LOCALE_WARNING_MSG - % (fs_encoding, default_encoding, used_locale.strip()) + NON_UTF8_LOCALE_WARNING_MSG % (fs_encoding, default_encoding, used_locale.strip()) ) is_debug_enabled = cfg.CONF.debug or cfg.CONF.system.debug @@ -197,9 +197,7 @@ def setup( except KeyError as e: tb_msg = traceback.format_exc() if "log.setLevel" in tb_msg: - msg = ( - "Invalid log level selected. Log level names need to be all uppercase." - ) + msg = "Invalid log level selected. Log level names need to be all uppercase." msg += "\n\n" + getattr(e, "message", six.text_type(e)) raise KeyError(msg) else: @@ -214,8 +212,7 @@ def setup( # set to "INFO" and we already log messages with level AUDIT to a special dedicated log # file. ignore_audit_log_messages = ( - handler.level >= stdlib_logging.INFO - and handler.level < stdlib_logging.AUDIT + handler.level >= stdlib_logging.INFO and handler.level < stdlib_logging.AUDIT ) if not is_debug_enabled and ignore_audit_log_messages: try: @@ -224,10 +221,7 @@ def setup( # In case handler doesn't have name assigned, repr would throw handler_repr = "unknown" - LOG.debug( - 'Excluding log messages with level "AUDIT" for handler "%s"' - % (handler_repr) - ) + LOG.debug('Excluding log messages with level "AUDIT" for handler "%s"' % (handler_repr)) handler.addFilter(LogLevelFilter(log_levels=exclude_log_levels)) if not is_debug_enabled: @@ -285,11 +279,10 @@ def setup( # modules like jinja, stevedore, etc load files from disk on init which is slow and will be # detected as blocking operation, but this is not really an issue inside the service startup / # init phase. - if cfg.CONF.enable_eventlet_blocking_detection: - print("Eventlet long running / blocking operation detection logic enabled") - print(cfg.CONF.eventlet_blocking_detection_resolution) - eventlet.debug.hub_blocking_detection( - state=True, resolution=cfg.CONF.eventlet_blocking_detection_resolution + if cfg.CONF.enable_concurrency_blocking_detection: + blocking_detection( + cfg.CONF.enable_concurrency_blocking_detection, + cfg.CONF.concurrency_blocking_detection_resolution, ) @@ -354,9 +347,7 @@ def deregister_service(service, start_heart=True): coordinator = coordination.get_coordinator(start_heart=start_heart) member_id = coordination.get_member_id() - LOG.debug( - 'Leaving service registry group "%s" as member_id "%s"' % (group_id, member_id) - ) + LOG.debug('Leaving service registry group "%s" as member_id "%s"' % (group_id, member_id)) try: coordinator.leave_group(group_id).get() except (GroupNotCreated, MemberNotJoined): diff --git a/st2common/st2common/util/concurrency.py b/st2common/st2common/util/concurrency.py index 00b3e89061..9a73e2cac9 100644 --- a/st2common/st2common/util/concurrency.py +++ b/st2common/st2common/util/concurrency.py @@ -171,7 +171,7 @@ def get_default_green_pool_size(): return eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS elif CONCURRENCY_LIBRARY == "gevent": # matches what DEFAULT_MAX_SIMULTANEOUS_REQUESTS is for eventlet - return 1024 + return 1024 else: raise ValueError("Unsupported concurrency library") @@ -210,13 +210,35 @@ def green_pool_wait_all(pool): else: raise ValueError("Unsupported concurrency library") -def listen_server(host, port): + +def listen_server(host, port, backlog=50, **kwargs): + """ + Start listening on the host:port. + :backlog: the number of unaccepted connections that the system will allow before refusing new connections. + """ if CONCURRENCY_LIBRARY == "eventlet": - return eventlet.listen((host, port)) + return eventlet.listen((host, port), backlog=backlog, **kwargs) elif CONCURRENCY_LIBRARY == "gevent": import socket + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((host, port)) - return sock.listen(5) + return sock.listen(backlog) + else: + raise ValueError("Unsupported concurrency library") + + +def blocking_detection(enable=False, timeout=1.0): + if CONCURRENCY_LIBRARY == "eventlet": + print( + f"Eventlet long running / blocking operation detection logic enabled. Block timeout ({timeout})." + ) + eventlet.debug.hub_blocking_detection(enable_detection=enable, resolution=timeout) + elif CONCURRENCY_LIBRARY == "gevent": + print( + f"gEvent long running / blocking operation detection logic enabled. Block timeout ({timeout})." + ) + gevent.config.monitor_thread = enable + gevent.config.max_blocking_time = timeout else: raise ValueError("Unsupported concurrency library") From 4ac51cec3fce965e744d59eae2f9fc70869318bb Mon Sep 17 00:00:00 2001 From: Carlos Date: Fri, 6 Mar 2026 18:19:54 +0100 Subject: [PATCH 5/5] Move wsgi behind concurrency library. --- st2api/st2api/cmd/api.py | 20 +++++++++---------- st2auth/st2auth/cmd/api.py | 26 +++++++++++++------------ st2common/st2common/config.py | 12 ++++++------ st2common/st2common/util/concurrency.py | 23 +++++++++++++++++----- st2stream/st2stream/cmd/api.py | 24 ++++++----------------- 5 files changed, 53 insertions(+), 52 deletions(-) diff --git a/st2api/st2api/cmd/api.py b/st2api/st2api/cmd/api.py index b80f6f4bed..04bf85b526 100644 --- a/st2api/st2api/cmd/api.py +++ b/st2api/st2api/cmd/api.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,20 +13,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import sys - # NOTE: It's important that we perform monkey patch as early as possible before any other modules # are important, otherwise SSL support for MongoDB won't work. # See https://github.com/StackStorm/st2/issues/4832 and https://github.com/gevent/gevent/issues/1016 # for details. from st2common.util.monkey_patch import monkey_patch - monkey_patch() -import eventlet +import os +import sys + from oslo_config import cfg -from eventlet import wsgi +from st2common.util import concurrency from st2common import log as logging from st2common.service_setup import setup as common_setup @@ -79,11 +77,11 @@ def _run_server(): LOG.info("(PID=%s) ST2 API is serving on http://%s:%s.", os.getpid(), host, port) - max_pool_size = eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS - worker_pool = eventlet.GreenPool(max_pool_size) - sock = eventlet.listen((host, port)) + max_pool_size = concurrency.get_default_green_pool_size() + worker_pool = concurrency.get_green_pool_class()(max_pool_size) + sock = concurrency.listen_server(host, port) - wsgi.server( + concurrency.wsgi_server( sock, app.setup_app(), custom_pool=worker_pool, log=LOG, log_output=False ) return 0 diff --git a/st2auth/st2auth/cmd/api.py b/st2auth/st2auth/cmd/api.py index 7a379814e6..125ec6c305 100644 --- a/st2auth/st2auth/cmd/api.py +++ b/st2auth/st2auth/cmd/api.py @@ -14,10 +14,8 @@ # limitations under the License. from st2common.util.monkey_patch import monkey_patch - monkey_patch() -from st2common.util import concurrency import os import sys @@ -27,6 +25,7 @@ from st2common.service_setup import setup as common_setup from st2common.service_setup import teardown as common_teardown from st2common.service_setup import deregister_service +from st2common.util import concurrency from st2auth import config config.register_opts(ignore_errors=True) @@ -74,29 +73,32 @@ def _run_server(): cert_file_path = os.path.realpath(cfg.CONF.auth.cert) key_file_path = os.path.realpath(cfg.CONF.auth.key) - if use_ssl and not os.path.isfile(cert_file_path): - raise ValueError('Certificate file "%s" doesn\'t exist' % (cert_file_path)) - - if use_ssl and not os.path.isfile(key_file_path): - raise ValueError('Private key file "%s" doesn\'t exist' % (key_file_path)) - socket = concurrency.listen(host, port) if use_ssl: - socket = eventlet.wrap_ssl( + scheme = "https" + if not os.path.isfile(cert_file_path): + raise ValueError(f'Certificate file "{cert_file_path}" does not exist') + + if not os.path.isfile(key_file_path): + raise ValueError(f'Private key file "{key_file_path}" does not exist') + + socket = concurrency.wrap_ssl( socket, certfile=cert_file_path, keyfile=key_file_path, server_side=True ) + else: + scheme = "http" LOG.info('ST2 Auth API running in "%s" auth mode', cfg.CONF.auth.mode) LOG.info( "(PID=%s) ST2 Auth API is serving on %s://%s:%s.", os.getpid(), - "https" if use_ssl else "http", + scheme, host, port, ) - wsgi = concurrency.get_wsgi_module() - wsgi.server(socket, app.setup_app(), log=LOG, log_output=False) + + concurrency.wsgi_server(socket, app.setup_app(), log=LOG, log_output=False) return 0 diff --git a/st2common/st2common/config.py b/st2common/st2common/config.py index a9461951d1..53b5f737c1 100644 --- a/st2common/st2common/config.py +++ b/st2common/st2common/config.py @@ -759,8 +759,8 @@ def register_opts(ignore_errors=False): cfg.BoolOpt( "use-debugger", default=True, - help="Enables debugger. Note that using this option changes how the " - "eventlet library is used to support async IO. This could result in " + help="Enables debugger. Note that using this option changes how the " + "concurrency library is used to support async IO. This could result in " "failures that do not occur under normal operation.", ), cfg.BoolOpt( @@ -769,14 +769,14 @@ def register_opts(ignore_errors=False): help="Enable code profiler mode. Do not use in production.", ), cfg.BoolOpt( - "enable-eventlet-blocking-detection", + "enable-concurrency-blocking-detection", default=False, - help="Enable eventlet blocking detection logic. Do not use in production.", + help="Enable blocking detection logic in concurrency library. Do not use in production.", ), cfg.FloatOpt( - "eventlet-blocking-detection-resolution", + "concurrency-blocking-detection-resolution", default=0.5, - help="Resolution in seconds for eventlet blocking detection logic.", + help="Resolution in seconds for blocking detection logic in currency library.", ), ] diff --git a/st2common/st2common/util/concurrency.py b/st2common/st2common/util/concurrency.py index 9a73e2cac9..edad8770e1 100644 --- a/st2common/st2common/util/concurrency.py +++ b/st2common/st2common/util/concurrency.py @@ -76,20 +76,22 @@ def get_subprocess_module(): else: raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") - -def get_wsgi_module(): +# socket, app.setup_app(), log=LOG, log_output=False +# sock, app.setup_app(), custom_pool=worker_pool, log=LOG, log_output=False +# sock, app.setup_app(), custom_pool=worker_pool +def wsgi_server(socket, app, custom_pool=None, log=None, log_output=True, *args, **kwargs): if CONCURRENCY_LIBRARY == "eventlet": from eventlet import wsgi - return wsgi + wsgi.server(socket, app, custom_pool=custom_pool, log=log, log_output=log_output, *args, **kwargs) elif CONCURRENCY_LIBRARY == "gevent": from gevent import pywsgi - return pywsgi + # Figure out how to handle custom pool + pywsgi.WSGIServer(socket, app) else: raise ValueError(f"Unsupported concurrency library {CONCURRENCY_LIBRARY}") - def subprocess_popen(*args, **kwargs): if CONCURRENCY_LIBRARY == "eventlet": from eventlet.green import subprocess # pylint: disable=import-error @@ -227,6 +229,17 @@ def listen_server(host, port, backlog=50, **kwargs): else: raise ValueError("Unsupported concurrency library") +def wrap_ssl(socket, *args, **kwargs): + if CONCURRENCY_LIBRARY == "eventlet": + return eventlet.wrap_socket(socket, *args, **kwargs) + elif CONCURRENCY_LIBRARY == "gevent": + # Monkey patching in the caller module is required prior to + # calling wrap_ssl() or this may block. + import ssl + + return ssl.wrap_socket(socket, *args, **kwargs) + else: + raise ValueError("Unsupported concurrency library") def blocking_detection(enable=False, timeout=1.0): if CONCURRENCY_LIBRARY == "eventlet": diff --git a/st2stream/st2stream/cmd/api.py b/st2stream/st2stream/cmd/api.py index 08caa0a2bd..3b4b393695 100644 --- a/st2stream/st2stream/cmd/api.py +++ b/st2stream/st2stream/cmd/api.py @@ -1,4 +1,4 @@ -# Copyright 2020 The StackStorm Authors. +# Copyright 2020-2026 The StackStorm Authors. # Copyright 2019 Extreme Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,16 +14,12 @@ # limitations under the License. from st2common.util.monkey_patch import monkey_patch - monkey_patch() import os import sys -import eventlet - from oslo_config import cfg -from eventlet import wsgi from st2common import log as logging from st2common.service_setup import setup as common_setup @@ -42,14 +38,6 @@ __all__ = ["main"] -#eventlet.monkey_patch( -# os=True, -# select=True, -# socket=True, -# thread=False if "--use-debugger" in sys.argv else True, -# time=True, -#) - LOG = logging.getLogger(__name__) STREAM = "stream" @@ -76,8 +64,8 @@ def _setup(): capabilities=capabilities, ) - def _run_server(): + host = cfg.CONF.stream.host port = cfg.CONF.stream.port @@ -85,13 +73,13 @@ def _run_server(): "(PID=%s) ST2 Stream API is serving on http://%s:%s.", os.getpid(), host, port ) - max_pool_size = concurrency.get_default_green_pool_size() + max_pool_size = concurrency.get_default_green_pool_size() worker_pool = concurrency.get_green_pool_class()(max_pool_size) - sock = concurrency.listen_server(host, port) + sock = concurrency.listen_server(host, port) def queue_shutdown(signal_number, stack_frame): deregister_service(STREAM) - eventlet.spawn_n( + concurrent.spawn( shutdown_server_kill_pending_requests, sock=sock, worker_pool=worker_pool, @@ -103,7 +91,7 @@ def queue_shutdown(signal_number, stack_frame): # will still want to kill long running stream requests. register_stream_signal_handlers(handler_func=queue_shutdown) - wsgi.server(sock, app.setup_app(), custom_pool=worker_pool) + concurrency.wsgi_server(sock, app.setup_app(), custom_pool=worker_pool) return 0