processcube-etw-library 2026.1.22.120215b0__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.
Files changed (27) hide show
  1. processcube_etw_library-2026.1.22.120215b0/.github/workflows/build_and_publish.yml +55 -0
  2. processcube_etw_library-2026.1.22.120215b0/.gitignore +8 -0
  3. processcube_etw_library-2026.1.22.120215b0/.python-version +1 -0
  4. processcube_etw_library-2026.1.22.120215b0/PKG-INFO +197 -0
  5. processcube_etw_library-2026.1.22.120215b0/README.md +184 -0
  6. processcube_etw_library-2026.1.22.120215b0/pyproject.toml +27 -0
  7. processcube_etw_library-2026.1.22.120215b0/setup.cfg +4 -0
  8. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/__init__.py +25 -0
  9. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/create_external_task_client.py +33 -0
  10. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/etw_app.py +98 -0
  11. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/health/__init__.py +23 -0
  12. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/health/built_in.py +34 -0
  13. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/health/check.py +45 -0
  14. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/health/handlers.py +44 -0
  15. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/health/models.py +43 -0
  16. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/health/registry.py +28 -0
  17. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/health/routes.py +27 -0
  18. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/identity_provider.py +87 -0
  19. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/server_config.py +30 -0
  20. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/settings.py +106 -0
  21. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library/typed_handler.py +49 -0
  22. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library.egg-info/PKG-INFO +197 -0
  23. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library.egg-info/SOURCES.txt +25 -0
  24. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library.egg-info/dependency_links.txt +1 -0
  25. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library.egg-info/requires.txt +4 -0
  26. processcube_etw_library-2026.1.22.120215b0/src/processcube_etw_library.egg-info/top_level.txt +1 -0
  27. processcube_etw_library-2026.1.22.120215b0/uv.lock +1604 -0
@@ -0,0 +1,55 @@
1
+ name: Build and Publish
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+ workflow_dispatch:
11
+
12
+ jobs:
13
+ build-and-publish:
14
+ runs-on: ubuntu-latest
15
+ environment:
16
+ name: pypi
17
+ permissions:
18
+ id-token: write
19
+ contents: read
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+
23
+ - name: Set up Python
24
+ uses: actions/setup-python@v6
25
+ with:
26
+ python-version-file: ".python-version"
27
+
28
+ - name: Install uv
29
+ uses: astral-sh/setup-uv@v7
30
+ with:
31
+ enable-cache: true
32
+ version: "0.9.26"
33
+
34
+ - name: Set version
35
+ id: set_version
36
+ run: |
37
+ DATE_VERSION=$(date +'%Y.%m.%d.%H%M%S')
38
+ if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
39
+ VERSION="${DATE_VERSION}"
40
+ else
41
+ VERSION="${DATE_VERSION}-beta"
42
+ fi
43
+ echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
44
+ echo "Setting version to: ${VERSION}"
45
+
46
+ - name: Install dependencies
47
+ run: uv sync --locked
48
+
49
+ - name: Build
50
+ run: uv build
51
+ env:
52
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ steps.set_version.outputs.VERSION }}
53
+
54
+ - name: Publish to PyPI
55
+ run: uv publish --token ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,8 @@
1
+ .DS_Store
2
+ .env
3
+ .env*
4
+ .venv/
5
+ __pycache__/
6
+ *.xlsx
7
+ *.egg-info/
8
+ build/
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.4
2
+ Name: processcube-etw-library
3
+ Version: 2026.1.22.120215b0
4
+ Summary: A library to create ETW apps with the ProcessCube platform.
5
+ Author-email: Jeremy Hill <jeremy.hill@profection.de>
6
+ License: MIT
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: fastapi[standard]>=0.128.0
10
+ Requires-Dist: oauth2-client>=1.4.2
11
+ Requires-Dist: processcube-client>=5.0.0
12
+ Requires-Dist: tenacity>=9.1.2
13
+
14
+ # ProcessCube ETW Library
15
+
16
+ Build External Task Workers (ETW) for ProcessCube, featuring health checks, typed handlers, and environment-based configuration.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ uv add processcube-etw-library
22
+ ```
23
+
24
+ ## Configuration
25
+
26
+ ### Environment Variables
27
+
28
+ The library uses environment variables for configuration. You can set these in your environment or in a `.env` file in your project root.
29
+
30
+ | Variable | Default | Description |
31
+ | ------------------------------------ | -------------------------------------- | ------------------------------------------------ |
32
+ | `PROCESSCUBE_ENGINE_URL` | `http://localhost:56000` | URL of the ProcessCube Engine |
33
+ | `PROCESSCUBE_AUTHORITY_URL` | Auto-discovered from engine | URL of the ProcessCube Authority (OAuth server) |
34
+ | `PROCESSCUBE_ETW_CLIENT_ID` | `test_etw` | OAuth client ID for the External Task Worker |
35
+ | `PROCESSCUBE_ETW_CLIENT_SECRET` | `3ef62eb3-fe49-4c2c-ba6f-73e4d234321b` | OAuth client secret for the External Task Worker |
36
+ | `PROCESSCUBE_ETW_CLIENT_SCOPES` | `engine_etw` | OAuth scopes for the External Task Worker |
37
+ | `MAX_GET_OAUTH_ACCESS_TOKEN_RETRIES` | `10` | Maximum retries for obtaining OAuth access token |
38
+ | `ENVIRONMENT` | `development` | Environment mode (`development` or `production`) |
39
+
40
+ #### Example `.env` File
41
+
42
+ ```env
43
+ PROCESSCUBE_ENGINE_URL=http://localhost:56000
44
+ PROCESSCUBE_ETW_CLIENT_ID=my_etw_client
45
+ PROCESSCUBE_ETW_CLIENT_SECRET=my_secret_key
46
+ PROCESSCUBE_ETW_CLIENT_SCOPES=engine_etw
47
+ ENVIRONMENT=production
48
+ ```
49
+
50
+ ### Extending Settings
51
+
52
+ You can extend the base settings class to add your own environment variables:
53
+
54
+ ```python
55
+ from pydantic import Field
56
+ from processcube_etw_library.settings import ETWSettings, load_settings
57
+
58
+ class MyAppSettings(ETWSettings):
59
+ database_url: str = Field(default="sqlite:///app.db")
60
+ api_key: str = Field(default="")
61
+
62
+ # Load settings with your custom class
63
+ settings = load_settings(MyAppSettings)
64
+ ```
65
+
66
+ ## Usage
67
+
68
+ ### Start the ETW Application
69
+
70
+ ```python
71
+ from processcube_etw_library import new_external_task_worker_app
72
+
73
+ # Create the application
74
+ app = new_external_task_worker_app()
75
+
76
+ # Run the application
77
+ app.run()
78
+ ```
79
+
80
+ ### Subscribe to External Task Topics
81
+
82
+ ```python
83
+ from processcube_etw_library import new_external_task_worker_app
84
+
85
+ app = new_external_task_worker_app()
86
+
87
+ def my_handler(task):
88
+ # Process the task
89
+ result = {"processed": True}
90
+ return result
91
+
92
+ # Subscribe to a topic
93
+ app.subscribe_to_external_task_for_topic("my-topic", my_handler)
94
+
95
+ app.run()
96
+ ```
97
+
98
+ ### Typed Handlers
99
+
100
+ Use typed handlers for automatic payload validation with Pydantic models:
101
+
102
+ ```python
103
+ from pydantic import BaseModel
104
+ from processcube_etw_library import new_external_task_worker_app
105
+
106
+ class MyInput(BaseModel):
107
+ name: str
108
+ value: int
109
+
110
+ class MyOutput(BaseModel):
111
+ result: str
112
+
113
+ app = new_external_task_worker_app()
114
+
115
+ def my_typed_handler(payload: MyInput) -> MyOutput:
116
+ return MyOutput(result=f"Processed {payload.name} with value {payload.value}")
117
+
118
+ app.subscribe_to_external_task_for_topic_typed("my-typed-topic", my_typed_handler)
119
+
120
+ app.run()
121
+ ```
122
+
123
+ ### Add a Custom Health Check
124
+
125
+ ```python
126
+ from processcube_etw_library import new_external_task_worker_app
127
+ from processcube_etw_library.health import HealthCheck, create_url_health_check
128
+
129
+ app = new_external_task_worker_app()
130
+
131
+ # Add a URL-based health check
132
+ app.add_health_check(
133
+ HealthCheck(
134
+ create_url_health_check("http://my-service:8080/health"),
135
+ service_name="My Service",
136
+ tags=["backend", "api"],
137
+ comments=["Checks if My Service is reachable"],
138
+ )
139
+ )
140
+
141
+ # Add a custom health check function
142
+ def check_database():
143
+ # Return True if healthy, False otherwise
144
+ try:
145
+ # Your database check logic here
146
+ return True
147
+ except Exception:
148
+ return False
149
+
150
+ app.add_health_check(
151
+ HealthCheck(
152
+ check_database,
153
+ service_name="Database",
154
+ tags=["backend", "database"],
155
+ comments=["Checks database connectivity"],
156
+ )
157
+ )
158
+
159
+ app.run()
160
+ ```
161
+
162
+ ### Managing Health Checks
163
+
164
+ ```python
165
+ # Get all registered health checks
166
+ checks = app.get_health_checks()
167
+
168
+ # Get a specific health check by service name
169
+ db_check = app.get_health_check("Database")
170
+
171
+ # Remove a health check
172
+ app.remove_health_check("Database")
173
+ ```
174
+
175
+ ### Disabling Built-in Health Checks
176
+
177
+ By default, the library registers health checks for the ProcessCube Engine and Authority. You can disable these:
178
+
179
+ ```python
180
+ app = new_external_task_worker_app(built_in_health_checks=False)
181
+ ```
182
+
183
+ ## Health Endpoints
184
+
185
+ The application exposes health endpoints at `/healthyz` and `/readyz` that return the status of all registered health checks.
186
+ To check if the application is running without performing health checks, use `/livez`.
187
+
188
+ ## Server Configuration
189
+
190
+ The server configuration is determined by the `ENVIRONMENT` variable:
191
+
192
+ | Setting | Development | Production |
193
+ | ---------- | ----------- | ---------- |
194
+ | Host | `0.0.0.0` | `0.0.0.0` |
195
+ | Port | `8000` | `8000` |
196
+ | Log Level | `debug` | `warning` |
197
+ | Access Log | `true` | `false` |
@@ -0,0 +1,184 @@
1
+ # ProcessCube ETW Library
2
+
3
+ Build External Task Workers (ETW) for ProcessCube, featuring health checks, typed handlers, and environment-based configuration.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ uv add processcube-etw-library
9
+ ```
10
+
11
+ ## Configuration
12
+
13
+ ### Environment Variables
14
+
15
+ The library uses environment variables for configuration. You can set these in your environment or in a `.env` file in your project root.
16
+
17
+ | Variable | Default | Description |
18
+ | ------------------------------------ | -------------------------------------- | ------------------------------------------------ |
19
+ | `PROCESSCUBE_ENGINE_URL` | `http://localhost:56000` | URL of the ProcessCube Engine |
20
+ | `PROCESSCUBE_AUTHORITY_URL` | Auto-discovered from engine | URL of the ProcessCube Authority (OAuth server) |
21
+ | `PROCESSCUBE_ETW_CLIENT_ID` | `test_etw` | OAuth client ID for the External Task Worker |
22
+ | `PROCESSCUBE_ETW_CLIENT_SECRET` | `3ef62eb3-fe49-4c2c-ba6f-73e4d234321b` | OAuth client secret for the External Task Worker |
23
+ | `PROCESSCUBE_ETW_CLIENT_SCOPES` | `engine_etw` | OAuth scopes for the External Task Worker |
24
+ | `MAX_GET_OAUTH_ACCESS_TOKEN_RETRIES` | `10` | Maximum retries for obtaining OAuth access token |
25
+ | `ENVIRONMENT` | `development` | Environment mode (`development` or `production`) |
26
+
27
+ #### Example `.env` File
28
+
29
+ ```env
30
+ PROCESSCUBE_ENGINE_URL=http://localhost:56000
31
+ PROCESSCUBE_ETW_CLIENT_ID=my_etw_client
32
+ PROCESSCUBE_ETW_CLIENT_SECRET=my_secret_key
33
+ PROCESSCUBE_ETW_CLIENT_SCOPES=engine_etw
34
+ ENVIRONMENT=production
35
+ ```
36
+
37
+ ### Extending Settings
38
+
39
+ You can extend the base settings class to add your own environment variables:
40
+
41
+ ```python
42
+ from pydantic import Field
43
+ from processcube_etw_library.settings import ETWSettings, load_settings
44
+
45
+ class MyAppSettings(ETWSettings):
46
+ database_url: str = Field(default="sqlite:///app.db")
47
+ api_key: str = Field(default="")
48
+
49
+ # Load settings with your custom class
50
+ settings = load_settings(MyAppSettings)
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ### Start the ETW Application
56
+
57
+ ```python
58
+ from processcube_etw_library import new_external_task_worker_app
59
+
60
+ # Create the application
61
+ app = new_external_task_worker_app()
62
+
63
+ # Run the application
64
+ app.run()
65
+ ```
66
+
67
+ ### Subscribe to External Task Topics
68
+
69
+ ```python
70
+ from processcube_etw_library import new_external_task_worker_app
71
+
72
+ app = new_external_task_worker_app()
73
+
74
+ def my_handler(task):
75
+ # Process the task
76
+ result = {"processed": True}
77
+ return result
78
+
79
+ # Subscribe to a topic
80
+ app.subscribe_to_external_task_for_topic("my-topic", my_handler)
81
+
82
+ app.run()
83
+ ```
84
+
85
+ ### Typed Handlers
86
+
87
+ Use typed handlers for automatic payload validation with Pydantic models:
88
+
89
+ ```python
90
+ from pydantic import BaseModel
91
+ from processcube_etw_library import new_external_task_worker_app
92
+
93
+ class MyInput(BaseModel):
94
+ name: str
95
+ value: int
96
+
97
+ class MyOutput(BaseModel):
98
+ result: str
99
+
100
+ app = new_external_task_worker_app()
101
+
102
+ def my_typed_handler(payload: MyInput) -> MyOutput:
103
+ return MyOutput(result=f"Processed {payload.name} with value {payload.value}")
104
+
105
+ app.subscribe_to_external_task_for_topic_typed("my-typed-topic", my_typed_handler)
106
+
107
+ app.run()
108
+ ```
109
+
110
+ ### Add a Custom Health Check
111
+
112
+ ```python
113
+ from processcube_etw_library import new_external_task_worker_app
114
+ from processcube_etw_library.health import HealthCheck, create_url_health_check
115
+
116
+ app = new_external_task_worker_app()
117
+
118
+ # Add a URL-based health check
119
+ app.add_health_check(
120
+ HealthCheck(
121
+ create_url_health_check("http://my-service:8080/health"),
122
+ service_name="My Service",
123
+ tags=["backend", "api"],
124
+ comments=["Checks if My Service is reachable"],
125
+ )
126
+ )
127
+
128
+ # Add a custom health check function
129
+ def check_database():
130
+ # Return True if healthy, False otherwise
131
+ try:
132
+ # Your database check logic here
133
+ return True
134
+ except Exception:
135
+ return False
136
+
137
+ app.add_health_check(
138
+ HealthCheck(
139
+ check_database,
140
+ service_name="Database",
141
+ tags=["backend", "database"],
142
+ comments=["Checks database connectivity"],
143
+ )
144
+ )
145
+
146
+ app.run()
147
+ ```
148
+
149
+ ### Managing Health Checks
150
+
151
+ ```python
152
+ # Get all registered health checks
153
+ checks = app.get_health_checks()
154
+
155
+ # Get a specific health check by service name
156
+ db_check = app.get_health_check("Database")
157
+
158
+ # Remove a health check
159
+ app.remove_health_check("Database")
160
+ ```
161
+
162
+ ### Disabling Built-in Health Checks
163
+
164
+ By default, the library registers health checks for the ProcessCube Engine and Authority. You can disable these:
165
+
166
+ ```python
167
+ app = new_external_task_worker_app(built_in_health_checks=False)
168
+ ```
169
+
170
+ ## Health Endpoints
171
+
172
+ The application exposes health endpoints at `/healthyz` and `/readyz` that return the status of all registered health checks.
173
+ To check if the application is running without performing health checks, use `/livez`.
174
+
175
+ ## Server Configuration
176
+
177
+ The server configuration is determined by the `ENVIRONMENT` variable:
178
+
179
+ | Setting | Development | Production |
180
+ | ---------- | ----------- | ---------- |
181
+ | Host | `0.0.0.0` | `0.0.0.0` |
182
+ | Port | `8000` | `8000` |
183
+ | Log Level | `debug` | `warning` |
184
+ | Access Log | `true` | `false` |
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel", "setuptools-scm>=8"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "processcube-etw-library"
7
+ dynamic = ["version"]
8
+ description = "A library to create ETW apps with the ProcessCube platform."
9
+ readme = "README.md"
10
+ authors = [{ name = "Jeremy Hill", email = "jeremy.hill@profection.de" }]
11
+ license = { text = "MIT" }
12
+ requires-python = ">=3.12"
13
+ dependencies = [
14
+ "fastapi[standard]>=0.128.0",
15
+ "oauth2-client>=1.4.2",
16
+ "processcube-client>=5.0.0",
17
+ "tenacity>=9.1.2",
18
+ ]
19
+
20
+ [tool.uv]
21
+ override-dependencies = ["nest-asyncio>=1.6.0"]
22
+
23
+ [tool.setuptools]
24
+ packages = ["processcube_etw_library"]
25
+ package-dir = { "" = "src" }
26
+
27
+ [tool.setuptools_scm]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,25 @@
1
+ # Prevent nest_asyncio from patching asyncio.run() in processcube_client - it breaks uvicorn's loop_factory
2
+ import nest_asyncio
3
+ nest_asyncio.apply = lambda *args, **kwargs: None
4
+
5
+ from .health import (
6
+ create_url_health_check,
7
+ HealthCheck,
8
+ HealthCheckModel,
9
+ HealthCheckRegistry,
10
+ HealthConditionInfo,
11
+ LivezResponse,
12
+ )
13
+ from .etw_app import new_external_task_worker_app
14
+ from .settings import load_settings, load_settings
15
+
16
+ __all__ = [
17
+ "create_url_health_check",
18
+ "HealthCheck",
19
+ "HealthCheckModel",
20
+ "HealthCheckRegistry",
21
+ "HealthConditionInfo",
22
+ "LivezResponse",
23
+ "new_external_task_worker_app",
24
+ "load_settings",
25
+ ]
@@ -0,0 +1,33 @@
1
+ # # Prevent nest_asyncio from patching asyncio.run() in processcube_client - it breaks uvicorn's loop_factory
2
+ # import nest_asyncio
3
+ # nest_asyncio.apply = lambda *args, **kwargs: None
4
+
5
+ from processcube_client.external_task import ExternalTaskClient
6
+
7
+ from .identity_provider import IdentityProvider
8
+ from .settings import load_settings
9
+
10
+
11
+ def create_external_task_client() -> ExternalTaskClient:
12
+ settings = load_settings()
13
+ authority_url = settings.processcube_authority_url
14
+ engine_url = settings.processcube_engine_url
15
+ client_name = settings.processcube_etw_client_id
16
+ client_secret = settings.processcube_etw_client_secret
17
+ client_scopes = settings.processcube_etw_client_scopes
18
+ max_get_oauth_access_token_retries = settings.max_get_oauth_access_token_retries
19
+
20
+ identity_provider = IdentityProvider(
21
+ authority_url,
22
+ client_name,
23
+ client_secret,
24
+ client_scopes,
25
+ max_get_oauth_access_token_retries,
26
+ )
27
+ client = ExternalTaskClient(
28
+ engine_url,
29
+ identity=identity_provider,
30
+ install_signals=False,
31
+ )
32
+
33
+ return client
@@ -0,0 +1,98 @@
1
+ import asyncio
2
+ from concurrent.futures import ThreadPoolExecutor
3
+ from contextlib import asynccontextmanager
4
+ from typing import Callable, Optional
5
+
6
+ from fastapi import FastAPI
7
+ import uvicorn
8
+
9
+ from .health import (
10
+ add_built_in_health_checks,
11
+ HealthCheck,
12
+ HealthCheckRegistry,
13
+ setup_health_routes
14
+ )
15
+ from .create_external_task_client import create_external_task_client
16
+ from .server_config import get_server_config
17
+ from .typed_handler import create_typed_handler_wrapper
18
+ from processcube_client.external_task import ExternalTaskClient
19
+
20
+
21
+ class ExternalTaskWorkerApp:
22
+ _etw_client: ExternalTaskClient
23
+ _health_registry: HealthCheckRegistry
24
+ _executor: ThreadPoolExecutor
25
+ _etw_future: Optional[asyncio.Future]
26
+ _app: FastAPI
27
+
28
+ def __init__(
29
+ self, etw_client: ExternalTaskClient, built_in_health_checks: bool = True
30
+ ):
31
+ self._executor = ThreadPoolExecutor(max_workers=1)
32
+ self._etw_future = None
33
+ self._etw_client = etw_client
34
+ self._app = FastAPI(lifespan=self._lifespan)
35
+ self._health_registry = HealthCheckRegistry()
36
+ if built_in_health_checks:
37
+ add_built_in_health_checks(self._health_registry)
38
+ setup_health_routes(self._app, self._health_registry)
39
+
40
+ @asynccontextmanager
41
+ async def _lifespan(self, app: FastAPI):
42
+ loop = asyncio.get_running_loop()
43
+ self._etw_future = loop.run_in_executor(self._executor, self._etw_client.start)
44
+
45
+ yield
46
+
47
+ loop = asyncio.get_running_loop()
48
+ await loop.run_in_executor(None, self._etw_client.stop)
49
+
50
+ if self._etw_future is not None and not self._etw_future.done():
51
+ self._etw_future.cancel()
52
+ try:
53
+ await self._etw_future
54
+ except asyncio.CancelledError:
55
+ pass
56
+
57
+ self._executor.shutdown(wait=False)
58
+
59
+ @property
60
+ def fastapi_app(self) -> FastAPI:
61
+ return self._app
62
+
63
+ def run(self) -> None:
64
+ config = get_server_config()
65
+ uvicorn.run(self._app, **config)
66
+
67
+ def subscribe_to_external_task_for_topic(
68
+ self, topic: str, handler: Callable, **options
69
+ ) -> None:
70
+ self._etw_client.subscribe_to_external_task_topic(topic, handler, **options)
71
+
72
+ def subscribe_to_external_task_for_topic_typed(
73
+ self, topic: str, handler: Callable, **options
74
+ ) -> None:
75
+ wrapper = create_typed_handler_wrapper(handler)
76
+ self._etw_client.subscribe_to_external_task_topic(topic, wrapper, **options)
77
+
78
+ def add_health_check(self, check: HealthCheck) -> None:
79
+ self._health_registry.register(check)
80
+
81
+ def remove_health_check(self, service_name: str) -> bool:
82
+ return self._health_registry.unregister(service_name)
83
+
84
+ def get_health_checks(self) -> list[HealthCheck]:
85
+ return self._health_registry.get_all()
86
+
87
+ def get_health_check(self, service_name: str) -> Optional[HealthCheck]:
88
+ return self._health_registry.get_by_name(service_name)
89
+
90
+
91
+ def new_external_task_worker_app(
92
+ built_in_health_checks: bool = True,
93
+ ) -> ExternalTaskWorkerApp:
94
+ external_task_client = create_external_task_client()
95
+
96
+ return ExternalTaskWorkerApp(
97
+ external_task_client, built_in_health_checks=built_in_health_checks
98
+ )
@@ -0,0 +1,23 @@
1
+ from .check import HealthCheck, create_url_health_check
2
+ from .handlers import health_check
3
+ from .models import (
4
+ HealthCheckEntityModel,
5
+ HealthCheckModel,
6
+ HealthConditionInfo,
7
+ LivezResponse,
8
+ )
9
+ from .registry import HealthCheckRegistry
10
+ from .built_in import add_built_in_health_checks
11
+ from .routes import setup_health_routes
12
+
13
+ __all__ = [
14
+ "add_built_in_health_checks",
15
+ "create_url_health_check",
16
+ "health_check",
17
+ "HealthCheck",
18
+ "HealthCheckEntityModel",
19
+ "HealthCheckModel",
20
+ "HealthCheckRegistry",
21
+ "HealthConditionInfo",
22
+ "LivezResponse",
23
+ ]
@@ -0,0 +1,34 @@
1
+ from ..settings import load_settings
2
+ from .check import HealthCheck, create_url_health_check
3
+ from .registry import HealthCheckRegistry
4
+
5
+
6
+ def add_built_in_health_checks(registry: HealthCheckRegistry) -> None:
7
+ settings = load_settings()
8
+
9
+ engine_url = (
10
+ settings.processcube_engine_url.strip("/")
11
+ + "/atlas_engine/api/v1/info"
12
+ )
13
+
14
+ authority_url = (
15
+ settings.processcube_authority_url.strip("/")
16
+ + "/.well-known/openid-configuration"
17
+ )
18
+
19
+ registry.register(
20
+ HealthCheck(
21
+ create_url_health_check(engine_url),
22
+ service_name="ProcessCube Engine",
23
+ tags=["core", "backend"],
24
+ comments=["Checks if the ProcessCube Engine is reachable"],
25
+ )
26
+ )
27
+ registry.register(
28
+ HealthCheck(
29
+ create_url_health_check(authority_url),
30
+ service_name="ProcessCube Authority",
31
+ tags=["core", "auth"],
32
+ comments=["Checks if the ProcessCube Authority is reachable"],
33
+ )
34
+ )