csu 2.2.4__tar.gz → 2.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {csu-2.2.4 → csu-2.2.5}/.bumpversion.cfg +1 -1
- {csu-2.2.4 → csu-2.2.5}/.cookiecutterrc +1 -1
- {csu-2.2.4 → csu-2.2.5}/PKG-INFO +3 -3
- {csu-2.2.4 → csu-2.2.5}/README.rst +2 -2
- {csu-2.2.4 → csu-2.2.5}/pyproject.toml +1 -1
- {csu-2.2.4 → csu-2.2.5}/src/csu/__init__.py +1 -1
- {csu-2.2.4 → csu-2.2.5}/src/csu/worker/__init__.py +0 -4
- csu-2.2.5/src/csu/worker/asgi.py +74 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/worker/engine.py +5 -3
- {csu-2.2.4 → csu-2.2.5}/src/csu/worker/models.py +3 -1
- {csu-2.2.4 → csu-2.2.5}/src/csu.egg-info/PKG-INFO +3 -3
- csu-2.2.5/tests/test_exampleworker.py +164 -0
- csu-2.2.4/src/csu/worker/asgi.py +0 -36
- csu-2.2.4/tests/test_exampleworker.py +0 -164
- {csu-2.2.4 → csu-2.2.5}/.coveragerc +0 -0
- {csu-2.2.4 → csu-2.2.5}/.editorconfig +0 -0
- {csu-2.2.4 → csu-2.2.5}/.github/workflows/github-actions.yml +0 -0
- {csu-2.2.4 → csu-2.2.5}/.pre-commit-config.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/.taplo.toml +0 -0
- {csu-2.2.4 → csu-2.2.5}/AUTHORS.rst +0 -0
- {csu-2.2.4 → csu-2.2.5}/CHANGELOG.rst +0 -0
- {csu-2.2.4 → csu-2.2.5}/CONTRIBUTING.rst +0 -0
- {csu-2.2.4 → csu-2.2.5}/LICENSE +0 -0
- {csu-2.2.4 → csu-2.2.5}/MANIFEST.in +0 -0
- {csu-2.2.4 → csu-2.2.5}/ci/bootstrap.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/ci/requirements.txt +0 -0
- {csu-2.2.4 → csu-2.2.5}/ci/templates/.github/workflows/github-actions.yml +0 -0
- {csu-2.2.4 → csu-2.2.5}/pytest.ini +0 -0
- {csu-2.2.4 → csu-2.2.5}/setup.cfg +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/admin.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/conf.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/consts.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/__init__.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/auth.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/fields.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/forms.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/perms.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/phonenumber.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/serializers.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/test_auth.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/test_fields.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/test_forms.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/test_phonenumber.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/test_serializers.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/drf/views.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/enums.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/env.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/exceptions.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/export.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/fixups.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/forms/__init__.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/forms/crispy.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/forms/fields.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/gettext.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/gettext_lazy.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/locale/ro/LC_MESSAGES/django.mo +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/locale/ro/LC_MESSAGES/django.po +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/logging.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/management.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/models.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/query.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/routers.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/service.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/templates/api_exception.html +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/templates/forms/widgets/opaquewidget.html +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_consts.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_env.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_exceptions.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_logging.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_management.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_service.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_timezones.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_utils.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/test_xml.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/timezones.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/utils.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/views.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/worker/admin.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/worker/enums.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/worker/job.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/worker/registry.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/wsgi.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu/xml.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu.egg-info/SOURCES.txt +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu.egg-info/dependency_links.txt +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu.egg-info/requires.txt +0 -0
- {csu-2.2.4 → csu-2.2.5}/src/csu.egg-info/top_level.txt +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/cassettes/test_service/test_custom_context.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/cassettes/test_service/test_custom_context_0_retries.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/cassettes/test_service/test_decoding.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/cassettes/test_service/test_error.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/cassettes/test_service/test_logging.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/cassettes/test_service/test_redirects.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/cassettes/test_service_auth/test_async.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/cassettes/test_service_auth/test_sync.yaml +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/conftest.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/exampleworker.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/test_models.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/test_service.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/test_service_auth.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/test_views.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/test_worker.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/testproject/__init__.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/testproject/fixtures/testuser.json +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/testproject/models.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/testproject/settings.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tests/testproject/urls.py +0 -0
- {csu-2.2.4 → csu-2.2.5}/tox.ini +0 -0
{csu-2.2.4 → csu-2.2.5}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csu
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5
|
|
4
4
|
Summary: Clean Slate Utils - bunch of utility code, mostly Django/DRF specific.
|
|
5
5
|
Author-email: Ionel Cristian Mărieș <contact@ionelmc.ro>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -77,9 +77,9 @@ Overview
|
|
|
77
77
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
78
78
|
:alt: Supported implementations
|
|
79
79
|
:target: https://pypi.org/project/csu
|
|
80
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.2.
|
|
80
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.2.5.svg
|
|
81
81
|
:alt: Commits since latest release
|
|
82
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.2.
|
|
82
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.2.5...main
|
|
83
83
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
84
84
|
:alt: Scrutinizer Status
|
|
85
85
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -34,9 +34,9 @@ Overview
|
|
|
34
34
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
35
35
|
:alt: Supported implementations
|
|
36
36
|
:target: https://pypi.org/project/csu
|
|
37
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.2.
|
|
37
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.2.5.svg
|
|
38
38
|
:alt: Commits since latest release
|
|
39
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.2.
|
|
39
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.2.5...main
|
|
40
40
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
41
41
|
:alt: Scrutinizer Status
|
|
42
42
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from logging import getLogger
|
|
2
|
+
|
|
3
|
+
import django
|
|
4
|
+
from asgiref.typing import ASGIReceiveCallable
|
|
5
|
+
from asgiref.typing import ASGIReceiveEvent
|
|
6
|
+
from asgiref.typing import ASGISendCallable
|
|
7
|
+
from asgiref.typing import LifespanShutdownCompleteEvent
|
|
8
|
+
from asgiref.typing import LifespanShutdownFailedEvent
|
|
9
|
+
from asgiref.typing import LifespanStartupCompleteEvent
|
|
10
|
+
from asgiref.typing import LifespanStartupFailedEvent
|
|
11
|
+
from django.core.handlers.asgi import ASGIHandler
|
|
12
|
+
|
|
13
|
+
from ..utils import lazy_import_classproperty
|
|
14
|
+
|
|
15
|
+
logger = getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class WorkerLifespanASGIHandler(ASGIHandler):
|
|
19
|
+
async def __call__(self, scope, receive: ASGIReceiveCallable, send) -> None:
|
|
20
|
+
if scope["type"] == "lifespan":
|
|
21
|
+
await self.handle_lifespan(receive, send)
|
|
22
|
+
else:
|
|
23
|
+
await super().__call__(scope, receive, send)
|
|
24
|
+
|
|
25
|
+
engine_registry = lazy_import_classproperty("csu.worker.registry.REGISTRY")
|
|
26
|
+
|
|
27
|
+
async def handle_start_engines(self):
|
|
28
|
+
registry = self.engine_registry
|
|
29
|
+
logger.info("Found %s registered engines.", len(registry))
|
|
30
|
+
for module_name, engine in registry.items():
|
|
31
|
+
logger.info("Starting engine for %s: %s...", module_name, engine)
|
|
32
|
+
if engine.shutdown_on:
|
|
33
|
+
raise RuntimeError(f"Engine {type(engine)} shutdown_on should be empty, not {engine.shutdown_on}!")
|
|
34
|
+
await engine.start()
|
|
35
|
+
logger.info(
|
|
36
|
+
"Started %s engines: \n %s",
|
|
37
|
+
len(registry),
|
|
38
|
+
"\n ".join(f"{module_name}: {engine}" for module_name, engine in registry.items()),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
async def handle_stop_engines(self):
|
|
42
|
+
registry = self.engine_registry
|
|
43
|
+
logger.info("Stopping %s registered engines.", len(registry))
|
|
44
|
+
for engine in registry.values():
|
|
45
|
+
await engine.stop(graceful=True)
|
|
46
|
+
|
|
47
|
+
async def handle_lifespan(self, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None:
|
|
48
|
+
while True:
|
|
49
|
+
message: ASGIReceiveEvent = await receive()
|
|
50
|
+
match message["type"]:
|
|
51
|
+
case "lifespan.startup":
|
|
52
|
+
try:
|
|
53
|
+
await self.handle_start_engines()
|
|
54
|
+
except Exception as exc:
|
|
55
|
+
await send(LifespanStartupFailedEvent(type="lifespan.startup.failed", message=str(exc)))
|
|
56
|
+
raise
|
|
57
|
+
else:
|
|
58
|
+
await send(LifespanStartupCompleteEvent(type="lifespan.startup.complete"))
|
|
59
|
+
case "lifespan.shutdown":
|
|
60
|
+
try:
|
|
61
|
+
await self.handle_stop_engines()
|
|
62
|
+
except Exception as exc:
|
|
63
|
+
await send(LifespanShutdownFailedEvent(type="lifespan.shutdown.failed", message=str(exc)))
|
|
64
|
+
raise
|
|
65
|
+
else:
|
|
66
|
+
await send(LifespanShutdownCompleteEvent(type="lifespan.shutdown.complete"))
|
|
67
|
+
return
|
|
68
|
+
case _:
|
|
69
|
+
raise ValueError(f"Unexpected message type: {message['type']!r}", message)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_worker_lifespan_application() -> WorkerLifespanASGIHandler:
|
|
73
|
+
django.setup(set_prefix=False)
|
|
74
|
+
return WorkerLifespanASGIHandler()
|
|
@@ -18,6 +18,7 @@ from datetime import timedelta
|
|
|
18
18
|
from enum import Flag
|
|
19
19
|
from enum import auto
|
|
20
20
|
from functools import partial
|
|
21
|
+
from logging import getLogger
|
|
21
22
|
from random import randint
|
|
22
23
|
from typing import ClassVar
|
|
23
24
|
from typing import Protocol
|
|
@@ -26,10 +27,11 @@ from datetimerange import DateTimeRange
|
|
|
26
27
|
|
|
27
28
|
from ..exceptions import InternalServiceError
|
|
28
29
|
from ..timezones import naivenow
|
|
29
|
-
from . import logger
|
|
30
30
|
from .enums import WorkerState
|
|
31
31
|
from .job import Job
|
|
32
32
|
|
|
33
|
+
logger = getLogger(__name__)
|
|
34
|
+
|
|
33
35
|
|
|
34
36
|
class TaskProtocol(Protocol):
|
|
35
37
|
job_kwargs: dict
|
|
@@ -270,7 +272,7 @@ class AbstractEngine(ABC):
|
|
|
270
272
|
workers: list[AbstractWorker]
|
|
271
273
|
queue: Queue = None
|
|
272
274
|
queue_sem: Semaphore
|
|
273
|
-
shutdown_on: Iterable[
|
|
275
|
+
shutdown_on: Iterable[signal.Signals] = (signal.SIGINT, signal.SIGTERM)
|
|
274
276
|
shutdown_requested = False
|
|
275
277
|
shutdown_tasks: ClassVar[dict[bool, asyncio.Task]] = {}
|
|
276
278
|
if sys.platform == "win32":
|
|
@@ -322,7 +324,7 @@ class AbstractEngine(ABC):
|
|
|
322
324
|
for sig in self.shutdown_on:
|
|
323
325
|
loop.add_signal_handler(sig, self.shutdown_handler, sig)
|
|
324
326
|
|
|
325
|
-
def shutdown_handler(self, sig):
|
|
327
|
+
def shutdown_handler(self, sig: signal.Signals) -> None:
|
|
326
328
|
sig_name = sig.name
|
|
327
329
|
graceful = not self.shutdown_requested
|
|
328
330
|
logger.info("%s.shutdown_handler(%s) %s", self, sig_name, "GRACEFUL" if graceful else "FORCED")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
from asyncio import CancelledError
|
|
3
3
|
from datetime import timedelta
|
|
4
|
+
from logging import getLogger
|
|
4
5
|
from random import SystemRandom
|
|
5
6
|
|
|
6
7
|
from asgiref.sync import sync_to_async
|
|
@@ -11,11 +12,12 @@ from django.db.models import F
|
|
|
11
12
|
from django.db.models import Q
|
|
12
13
|
|
|
13
14
|
from ..timezones import utcnow
|
|
14
|
-
from . import logger
|
|
15
15
|
from .engine import AbstractConsumer
|
|
16
16
|
from .engine import AbstractProducer
|
|
17
17
|
from .job import Job
|
|
18
18
|
|
|
19
|
+
logger = getLogger(__name__)
|
|
20
|
+
|
|
19
21
|
|
|
20
22
|
def get_random_float(system_random=SystemRandom()): # noqa: B008
|
|
21
23
|
return system_random.random()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csu
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5
|
|
4
4
|
Summary: Clean Slate Utils - bunch of utility code, mostly Django/DRF specific.
|
|
5
5
|
Author-email: Ionel Cristian Mărieș <contact@ionelmc.ro>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -77,9 +77,9 @@ Overview
|
|
|
77
77
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
78
78
|
:alt: Supported implementations
|
|
79
79
|
:target: https://pypi.org/project/csu
|
|
80
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.2.
|
|
80
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.2.5.svg
|
|
81
81
|
:alt: Commits since latest release
|
|
82
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.2.
|
|
82
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.2.5...main
|
|
83
83
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
84
84
|
:alt: Scrutinizer Status
|
|
85
85
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import signal
|
|
2
|
+
import sys
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from process_tests import TestProcess
|
|
6
|
+
from process_tests import dump_on_error
|
|
7
|
+
from process_tests import wait_for_strings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_noskip():
|
|
11
|
+
with TestProcess(sys.executable, "-mexampleworker", "3", "0", "1000", "4") as target, dump_on_error(target.read):
|
|
12
|
+
wait_for_strings(
|
|
13
|
+
target.read,
|
|
14
|
+
5,
|
|
15
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/UNKNOWN) started.",
|
|
16
|
+
"INFO:csu.worker.engine:ExampleConsumer(2/UNKNOWN) started.",
|
|
17
|
+
"INFO:csu.worker.engine:ExampleConsumer(3/UNKNOWN) started.",
|
|
18
|
+
"INFO:csu.worker.engine:ExampleProducer(1/UNKNOWN) started.",
|
|
19
|
+
"INFO:csu.worker.engine:ExampleProducer(1/UNKNOWN).run() started.",
|
|
20
|
+
"PRODUCER fetch_task @ 1 RETURN",
|
|
21
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=1))",
|
|
22
|
+
"INFO:csu.worker.engine:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=1).done of NoOpTask(id=1).",
|
|
23
|
+
"PRODUCER fetch_task @ 2 RETURN",
|
|
24
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/1q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=2))",
|
|
25
|
+
"INFO:csu.worker.engine:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=2).done of NoOpTask(id=2).",
|
|
26
|
+
"PRODUCER fetch_task @ 3 RETURN",
|
|
27
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/2q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=3))",
|
|
28
|
+
"INFO:csu.worker.engine:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=3).done of NoOpTask(id=3).",
|
|
29
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=1)",
|
|
30
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/WORKING).run() - performing...",
|
|
31
|
+
"CONSUMER 0 perform_work JOB 1 START",
|
|
32
|
+
"INFO:csu.worker.engine:ExampleConsumer(2/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=2)",
|
|
33
|
+
"INFO:csu.worker.engine:ExampleConsumer(2/WORKING).run() - performing...",
|
|
34
|
+
"CONSUMER 1 perform_work JOB 2 START",
|
|
35
|
+
"INFO:csu.worker.engine:ExampleConsumer(3/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=3)",
|
|
36
|
+
"INFO:csu.worker.engine:ExampleConsumer(3/WORKING).run() - performing...",
|
|
37
|
+
"CONSUMER 2 perform_work JOB 3 START",
|
|
38
|
+
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
39
|
+
"CONSUMER 0 save_result JOB 1",
|
|
40
|
+
"CONSUMER 1 perform_work JOB 2 DONE",
|
|
41
|
+
"CONSUMER 1 save_result JOB 2",
|
|
42
|
+
"CONSUMER 2 perform_work JOB 3 DONE",
|
|
43
|
+
"CONSUMER 2 save_result JOB 3",
|
|
44
|
+
"PRODUCER fetch_task @ 4 RETURN",
|
|
45
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=4))",
|
|
46
|
+
"INFO:csu.worker.engine:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=4).done of NoOpTask(id=4).",
|
|
47
|
+
"PRODUCER fetch_task @ 5 EXHAUSTED",
|
|
48
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=4)",
|
|
49
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/WORKING).run() - performing...",
|
|
50
|
+
"CONSUMER 0 perform_work JOB 4 START",
|
|
51
|
+
"PRODUCER fetch_task @ 6 EXHAUSTED",
|
|
52
|
+
"CONSUMER 0 perform_work JOB 4 DONE",
|
|
53
|
+
"CONSUMER 0 save_result JOB 4",
|
|
54
|
+
"PRODUCER fetch_task @ 7 EXHAUSTED",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_skip():
|
|
59
|
+
with TestProcess(sys.executable, "-mexampleworker", "3", "2", "100", "4") as target, dump_on_error(target.read):
|
|
60
|
+
wait_for_strings(
|
|
61
|
+
target.read,
|
|
62
|
+
5,
|
|
63
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/UNKNOWN) started.",
|
|
64
|
+
"INFO:csu.worker.engine:ExampleConsumer(2/UNKNOWN) started.",
|
|
65
|
+
"INFO:csu.worker.engine:ExampleConsumer(3/UNKNOWN) started.",
|
|
66
|
+
"INFO:csu.worker.engine:ExampleProducer(1/UNKNOWN) started.",
|
|
67
|
+
"INFO:csu.worker.engine:ExampleProducer(1/UNKNOWN).run() started.",
|
|
68
|
+
"PRODUCER fetch_task @ 1 RETURN",
|
|
69
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=1))",
|
|
70
|
+
"INFO:csu.worker.engine:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=1).done of NoOpTask(id=1).",
|
|
71
|
+
"PRODUCER fetch_task @ 2 SKIP",
|
|
72
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=1)",
|
|
73
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/WORKING).run() - performing...",
|
|
74
|
+
"CONSUMER 0 perform_work JOB 1 START",
|
|
75
|
+
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
76
|
+
"CONSUMER 0 save_result JOB 1",
|
|
77
|
+
"PRODUCER fetch_task @ 3 RETURN",
|
|
78
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=3))",
|
|
79
|
+
"INFO:csu.worker.engine:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=3).done of NoOpTask(id=3).",
|
|
80
|
+
"PRODUCER fetch_task @ 4 SKIP",
|
|
81
|
+
"INFO:csu.worker.engine:ExampleConsumer(2/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=3)",
|
|
82
|
+
"INFO:csu.worker.engine:ExampleConsumer(2/WORKING).run() - performing...",
|
|
83
|
+
"CONSUMER 1 perform_work JOB 3 START",
|
|
84
|
+
"CONSUMER 1 perform_work JOB 3 DONE",
|
|
85
|
+
"CONSUMER 1 save_result JOB 3",
|
|
86
|
+
"PRODUCER fetch_task @ 5 EXHAUSTED",
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_graceful_shutdown():
|
|
91
|
+
with TestProcess(sys.executable, "-mexampleworker", "3", "0", "1000", "100") as target, dump_on_error(target.read):
|
|
92
|
+
wait_for_strings(
|
|
93
|
+
target.read,
|
|
94
|
+
15,
|
|
95
|
+
"PRODUCER fetch_task @ 1 RETURN",
|
|
96
|
+
)
|
|
97
|
+
target.proc.send_signal(signal.SIGINT)
|
|
98
|
+
wait_for_strings(
|
|
99
|
+
target.read,
|
|
100
|
+
15,
|
|
101
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).shutdown_handler(SIGINT) GRACEFUL",
|
|
102
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).stop(graceful=True)",
|
|
103
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) stats: {'ExampleConsumer': {'WORKING': 3}, 'ExampleProducer': {'WAITING': 1}, 'ExampleEngine': {'JOBS': 3, 'QSIZE': 0, 'SEMVAL': 0}}",
|
|
104
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) worker 1: <__main__.ExampleConsumer object at ",
|
|
105
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) worker 2: <__main__.ExampleConsumer object at ",
|
|
106
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) worker 3: <__main__.ExampleConsumer object at ",
|
|
107
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) worker 4: <__main__.ExampleProducer object at ",
|
|
108
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) requesting workers to stop and awaiting 1 producers...",
|
|
109
|
+
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
110
|
+
"CONSUMER 0 save_result JOB 1",
|
|
111
|
+
"INFO:csu.worker.engine:ExampleProducer(1/WAITING).on_exit(",
|
|
112
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) flushing queue (0 items) and awaiting consumers...",
|
|
113
|
+
"INFO:csu.worker.engine:ExampleConsumer(1/SHUTDOWN).on_exit(",
|
|
114
|
+
"INFO:csu.worker.engine:ExampleConsumer(2/SHUTDOWN).on_exit(",
|
|
115
|
+
"INFO:csu.worker.engine:ExampleConsumer(3/SHUTDOWN).on_exit(",
|
|
116
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) shutdown complete.",
|
|
117
|
+
"DONE: {'ExampleConsumer': {'EXITED': 3}, 'ExampleProducer': {'EXITED': 1}, 'ExampleEngine': {'JOBS': 3, 'QSIZE': 0, 'SEMVAL': 2}}",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_forced_shutdown():
|
|
122
|
+
with TestProcess(sys.executable, "-mexampleworker", "3", "0", "2000", "100") as target, dump_on_error(target.read):
|
|
123
|
+
wait_for_strings(
|
|
124
|
+
target.read,
|
|
125
|
+
15,
|
|
126
|
+
"PRODUCER fetch_task @ 1 RETURN",
|
|
127
|
+
)
|
|
128
|
+
target.proc.send_signal(signal.SIGINT)
|
|
129
|
+
time.sleep(1)
|
|
130
|
+
target.proc.send_signal(signal.SIGTERM)
|
|
131
|
+
wait_for_strings(
|
|
132
|
+
target.read,
|
|
133
|
+
15,
|
|
134
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).shutdown_handler(SIGINT) GRACEFUL",
|
|
135
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).stop(graceful=True)",
|
|
136
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q) requesting workers to stop and awaiting 1 producers...",
|
|
137
|
+
"INFO:csu.worker.engine:ExampleEngine(4w/0q).shutdown_handler(SIGTERM) FORCED",
|
|
138
|
+
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
139
|
+
"CONSUMER 1 perform_work JOB 2 DONE",
|
|
140
|
+
"CONSUMER 2 perform_work JOB 3 DONE",
|
|
141
|
+
"DONE: {'ExampleConsumer': {'CANCELED': 3}, 'ExampleProducer': {'CANCELED': 1}, 'ExampleEngine': {'JOBS': 3, 'QSIZE': 0, 'SEMVAL': 0}}",
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_sem_rollback():
|
|
146
|
+
with TestProcess(sys.executable, "-mexampleworker", "1", "2", "10", "10") as target, dump_on_error(target.read):
|
|
147
|
+
wait_for_strings(
|
|
148
|
+
target.read,
|
|
149
|
+
15,
|
|
150
|
+
"PRODUCER fetch_task @ 1 RETURN",
|
|
151
|
+
"CONSUMER 0 perform_work JOB 1 START",
|
|
152
|
+
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
153
|
+
"CONSUMER 0 save_result JOB 1",
|
|
154
|
+
"PRODUCER fetch_task @ 2 SKIP",
|
|
155
|
+
"PRODUCER fetch_task @ 3 RETURN",
|
|
156
|
+
"CONSUMER 0 perform_work JOB 3 START",
|
|
157
|
+
"CONSUMER 0 perform_work JOB 3 DONE",
|
|
158
|
+
"CONSUMER 0 save_result JOB 3",
|
|
159
|
+
"PRODUCER fetch_task @ 4 SKIP",
|
|
160
|
+
"PRODUCER fetch_task @ 5 RETURN",
|
|
161
|
+
"CONSUMER 0 perform_work JOB 5 START",
|
|
162
|
+
"CONSUMER 0 perform_work JOB 5 DONE",
|
|
163
|
+
"CONSUMER 0 save_result JOB 5",
|
|
164
|
+
)
|
csu-2.2.4/src/csu/worker/asgi.py
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
from asgiref.typing import ASGIReceiveCallable
|
|
2
|
-
from asgiref.typing import ASGISendCallable
|
|
3
|
-
from asgiref.typing import Scope
|
|
4
|
-
from django.core.asgi import get_asgi_application
|
|
5
|
-
|
|
6
|
-
from . import logger
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def get_worker_lifespan_application():
|
|
10
|
-
django_application = get_asgi_application()
|
|
11
|
-
|
|
12
|
-
async def application_with_worker_lifespan(scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None:
|
|
13
|
-
if scope["type"] == "lifespan":
|
|
14
|
-
try:
|
|
15
|
-
from .registry import REGISTRY # noqa:PLC0415
|
|
16
|
-
|
|
17
|
-
while True:
|
|
18
|
-
message = await receive()
|
|
19
|
-
message_type = message["type"]
|
|
20
|
-
if message_type == "lifespan.startup":
|
|
21
|
-
logger.info("Found %s registered engines.", len(REGISTRY))
|
|
22
|
-
for module_name, engine in REGISTRY.items():
|
|
23
|
-
logger.info("Starting engine for %s: %s...", module_name, engine)
|
|
24
|
-
await engine.start()
|
|
25
|
-
await send({"type": "lifespan.startup.complete"})
|
|
26
|
-
if message_type == "lifespan.shutdown":
|
|
27
|
-
for engine in REGISTRY.values():
|
|
28
|
-
await engine.stop()
|
|
29
|
-
await send({"type": "lifespan.shutdown.complete"})
|
|
30
|
-
return
|
|
31
|
-
except Exception as exc:
|
|
32
|
-
logger.exception("Failed setting up lifespan: %r", exc)
|
|
33
|
-
else:
|
|
34
|
-
await django_application(scope, receive, send)
|
|
35
|
-
|
|
36
|
-
return application_with_worker_lifespan
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import signal
|
|
2
|
-
import sys
|
|
3
|
-
import time
|
|
4
|
-
|
|
5
|
-
from process_tests import TestProcess
|
|
6
|
-
from process_tests import dump_on_error
|
|
7
|
-
from process_tests import wait_for_strings
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def test_noskip():
|
|
11
|
-
with TestProcess(sys.executable, "-mexampleworker", "3", "0", "1000", "4") as target, dump_on_error(target.read):
|
|
12
|
-
wait_for_strings(
|
|
13
|
-
target.read,
|
|
14
|
-
5,
|
|
15
|
-
"INFO:worker:ExampleConsumer(1/UNKNOWN) started.",
|
|
16
|
-
"INFO:worker:ExampleConsumer(2/UNKNOWN) started.",
|
|
17
|
-
"INFO:worker:ExampleConsumer(3/UNKNOWN) started.",
|
|
18
|
-
"INFO:worker:ExampleProducer(1/UNKNOWN) started.",
|
|
19
|
-
"INFO:worker:ExampleProducer(1/UNKNOWN).run() started.",
|
|
20
|
-
"PRODUCER fetch_task @ 1 RETURN",
|
|
21
|
-
"INFO:worker:ExampleEngine(4w/0q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=1))",
|
|
22
|
-
"INFO:worker:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=1).done of NoOpTask(id=1).",
|
|
23
|
-
"PRODUCER fetch_task @ 2 RETURN",
|
|
24
|
-
"INFO:worker:ExampleEngine(4w/1q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=2))",
|
|
25
|
-
"INFO:worker:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=2).done of NoOpTask(id=2).",
|
|
26
|
-
"PRODUCER fetch_task @ 3 RETURN",
|
|
27
|
-
"INFO:worker:ExampleEngine(4w/2q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=3))",
|
|
28
|
-
"INFO:worker:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=3).done of NoOpTask(id=3).",
|
|
29
|
-
"INFO:worker:ExampleConsumer(1/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=1)",
|
|
30
|
-
"INFO:worker:ExampleConsumer(1/WORKING).run() - performing...",
|
|
31
|
-
"CONSUMER 0 perform_work JOB 1 START",
|
|
32
|
-
"INFO:worker:ExampleConsumer(2/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=2)",
|
|
33
|
-
"INFO:worker:ExampleConsumer(2/WORKING).run() - performing...",
|
|
34
|
-
"CONSUMER 1 perform_work JOB 2 START",
|
|
35
|
-
"INFO:worker:ExampleConsumer(3/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=3)",
|
|
36
|
-
"INFO:worker:ExampleConsumer(3/WORKING).run() - performing...",
|
|
37
|
-
"CONSUMER 2 perform_work JOB 3 START",
|
|
38
|
-
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
39
|
-
"CONSUMER 0 save_result JOB 1",
|
|
40
|
-
"CONSUMER 1 perform_work JOB 2 DONE",
|
|
41
|
-
"CONSUMER 1 save_result JOB 2",
|
|
42
|
-
"CONSUMER 2 perform_work JOB 3 DONE",
|
|
43
|
-
"CONSUMER 2 save_result JOB 3",
|
|
44
|
-
"PRODUCER fetch_task @ 4 RETURN",
|
|
45
|
-
"INFO:worker:ExampleEngine(4w/0q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=4))",
|
|
46
|
-
"INFO:worker:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=4).done of NoOpTask(id=4).",
|
|
47
|
-
"PRODUCER fetch_task @ 5 EXHAUSTED",
|
|
48
|
-
"INFO:worker:ExampleConsumer(1/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=4)",
|
|
49
|
-
"INFO:worker:ExampleConsumer(1/WORKING).run() - performing...",
|
|
50
|
-
"CONSUMER 0 perform_work JOB 4 START",
|
|
51
|
-
"PRODUCER fetch_task @ 6 EXHAUSTED",
|
|
52
|
-
"CONSUMER 0 perform_work JOB 4 DONE",
|
|
53
|
-
"CONSUMER 0 save_result JOB 4",
|
|
54
|
-
"PRODUCER fetch_task @ 7 EXHAUSTED",
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def test_skip():
|
|
59
|
-
with TestProcess(sys.executable, "-mexampleworker", "3", "2", "100", "4") as target, dump_on_error(target.read):
|
|
60
|
-
wait_for_strings(
|
|
61
|
-
target.read,
|
|
62
|
-
5,
|
|
63
|
-
"INFO:worker:ExampleConsumer(1/UNKNOWN) started.",
|
|
64
|
-
"INFO:worker:ExampleConsumer(2/UNKNOWN) started.",
|
|
65
|
-
"INFO:worker:ExampleConsumer(3/UNKNOWN) started.",
|
|
66
|
-
"INFO:worker:ExampleProducer(1/UNKNOWN) started.",
|
|
67
|
-
"INFO:worker:ExampleProducer(1/UNKNOWN).run() started.",
|
|
68
|
-
"PRODUCER fetch_task @ 1 RETURN",
|
|
69
|
-
"INFO:worker:ExampleEngine(4w/0q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=1))",
|
|
70
|
-
"INFO:worker:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=1).done of NoOpTask(id=1).",
|
|
71
|
-
"PRODUCER fetch_task @ 2 SKIP",
|
|
72
|
-
"INFO:worker:ExampleConsumer(1/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=1)",
|
|
73
|
-
"INFO:worker:ExampleConsumer(1/WORKING).run() - performing...",
|
|
74
|
-
"CONSUMER 0 perform_work JOB 1 START",
|
|
75
|
-
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
76
|
-
"CONSUMER 0 save_result JOB 1",
|
|
77
|
-
"PRODUCER fetch_task @ 3 RETURN",
|
|
78
|
-
"INFO:worker:ExampleEngine(4w/0q).push(ExampleJob(done=<Future pending>, started=<Future pending>, id=3))",
|
|
79
|
-
"INFO:worker:ExampleProducer(1/WORKING).run() awaiting ExampleJob(done=<Future pending>, started=<Future pending>, id=3).done of NoOpTask(id=3).",
|
|
80
|
-
"PRODUCER fetch_task @ 4 SKIP",
|
|
81
|
-
"INFO:worker:ExampleConsumer(2/READY).run() working on: ExampleJob(done=<Future pending>, started=<Future finished result=True>, id=3)",
|
|
82
|
-
"INFO:worker:ExampleConsumer(2/WORKING).run() - performing...",
|
|
83
|
-
"CONSUMER 1 perform_work JOB 3 START",
|
|
84
|
-
"CONSUMER 1 perform_work JOB 3 DONE",
|
|
85
|
-
"CONSUMER 1 save_result JOB 3",
|
|
86
|
-
"PRODUCER fetch_task @ 5 EXHAUSTED",
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def test_graceful_shutdown():
|
|
91
|
-
with TestProcess(sys.executable, "-mexampleworker", "3", "0", "1000", "100") as target, dump_on_error(target.read):
|
|
92
|
-
wait_for_strings(
|
|
93
|
-
target.read,
|
|
94
|
-
15,
|
|
95
|
-
"PRODUCER fetch_task @ 1 RETURN",
|
|
96
|
-
)
|
|
97
|
-
target.proc.send_signal(signal.SIGINT)
|
|
98
|
-
wait_for_strings(
|
|
99
|
-
target.read,
|
|
100
|
-
15,
|
|
101
|
-
"INFO:worker:ExampleEngine(4w/0q).shutdown_handler(SIGINT) GRACEFUL",
|
|
102
|
-
"INFO:worker:ExampleEngine(4w/0q).stop(graceful=True)",
|
|
103
|
-
"INFO:worker:ExampleEngine(4w/0q) stats: {'ExampleConsumer': {'WORKING': 3}, 'ExampleProducer': {'WAITING': 1}, 'ExampleEngine': {'JOBS': 3, 'QSIZE': 0, 'SEMVAL': 0}}",
|
|
104
|
-
"INFO:worker:ExampleEngine(4w/0q) worker 1: <__main__.ExampleConsumer object at ",
|
|
105
|
-
"INFO:worker:ExampleEngine(4w/0q) worker 2: <__main__.ExampleConsumer object at ",
|
|
106
|
-
"INFO:worker:ExampleEngine(4w/0q) worker 3: <__main__.ExampleConsumer object at ",
|
|
107
|
-
"INFO:worker:ExampleEngine(4w/0q) worker 4: <__main__.ExampleProducer object at ",
|
|
108
|
-
"INFO:worker:ExampleEngine(4w/0q) requesting workers to stop and awaiting 1 producers...",
|
|
109
|
-
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
110
|
-
"CONSUMER 0 save_result JOB 1",
|
|
111
|
-
"INFO:worker:ExampleProducer(1/WAITING).on_exit(",
|
|
112
|
-
"INFO:worker:ExampleEngine(4w/0q) flushing queue (0 items) and awaiting consumers...",
|
|
113
|
-
"INFO:worker:ExampleConsumer(1/SHUTDOWN).on_exit(",
|
|
114
|
-
"INFO:worker:ExampleConsumer(2/SHUTDOWN).on_exit(",
|
|
115
|
-
"INFO:worker:ExampleConsumer(3/SHUTDOWN).on_exit(",
|
|
116
|
-
"INFO:worker:ExampleEngine(4w/0q) shutdown complete.",
|
|
117
|
-
"DONE: {'ExampleConsumer': {'EXITED': 3}, 'ExampleProducer': {'EXITED': 1}, 'ExampleEngine': {'JOBS': 3, 'QSIZE': 0, 'SEMVAL': 2}}",
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def test_forced_shutdown():
|
|
122
|
-
with TestProcess(sys.executable, "-mexampleworker", "3", "0", "2000", "100") as target, dump_on_error(target.read):
|
|
123
|
-
wait_for_strings(
|
|
124
|
-
target.read,
|
|
125
|
-
15,
|
|
126
|
-
"PRODUCER fetch_task @ 1 RETURN",
|
|
127
|
-
)
|
|
128
|
-
target.proc.send_signal(signal.SIGINT)
|
|
129
|
-
time.sleep(1)
|
|
130
|
-
target.proc.send_signal(signal.SIGTERM)
|
|
131
|
-
wait_for_strings(
|
|
132
|
-
target.read,
|
|
133
|
-
15,
|
|
134
|
-
"INFO:worker:ExampleEngine(4w/0q).shutdown_handler(SIGINT) GRACEFUL",
|
|
135
|
-
"INFO:worker:ExampleEngine(4w/0q).stop(graceful=True)",
|
|
136
|
-
"INFO:worker:ExampleEngine(4w/0q) requesting workers to stop and awaiting 1 producers...",
|
|
137
|
-
"INFO:worker:ExampleEngine(4w/0q).shutdown_handler(SIGTERM) FORCED",
|
|
138
|
-
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
139
|
-
"CONSUMER 1 perform_work JOB 2 DONE",
|
|
140
|
-
"CONSUMER 2 perform_work JOB 3 DONE",
|
|
141
|
-
"DONE: {'ExampleConsumer': {'CANCELED': 3}, 'ExampleProducer': {'CANCELED': 1}, 'ExampleEngine': {'JOBS': 3, 'QSIZE': 0, 'SEMVAL': 0}}",
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
def test_sem_rollback():
|
|
146
|
-
with TestProcess(sys.executable, "-mexampleworker", "1", "2", "10", "10") as target, dump_on_error(target.read):
|
|
147
|
-
wait_for_strings(
|
|
148
|
-
target.read,
|
|
149
|
-
15,
|
|
150
|
-
"PRODUCER fetch_task @ 1 RETURN",
|
|
151
|
-
"CONSUMER 0 perform_work JOB 1 START",
|
|
152
|
-
"CONSUMER 0 perform_work JOB 1 DONE",
|
|
153
|
-
"CONSUMER 0 save_result JOB 1",
|
|
154
|
-
"PRODUCER fetch_task @ 2 SKIP",
|
|
155
|
-
"PRODUCER fetch_task @ 3 RETURN",
|
|
156
|
-
"CONSUMER 0 perform_work JOB 3 START",
|
|
157
|
-
"CONSUMER 0 perform_work JOB 3 DONE",
|
|
158
|
-
"CONSUMER 0 save_result JOB 3",
|
|
159
|
-
"PRODUCER fetch_task @ 4 SKIP",
|
|
160
|
-
"PRODUCER fetch_task @ 5 RETURN",
|
|
161
|
-
"CONSUMER 0 perform_work JOB 5 START",
|
|
162
|
-
"CONSUMER 0 perform_work JOB 5 DONE",
|
|
163
|
-
"CONSUMER 0 save_result JOB 5",
|
|
164
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csu-2.2.4 → csu-2.2.5}/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csu-2.2.4 → csu-2.2.5}/tox.ini
RENAMED
|
File without changes
|