gen-worker 0.1.0__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.
- gen_worker-0.1.0/.gitignore +22 -0
- gen_worker-0.1.0/PKG-INFO +232 -0
- gen_worker-0.1.0/README.md +202 -0
- gen_worker-0.1.0/examples/demo/README.md +12 -0
- gen_worker-0.1.0/examples/demo/pyproject.toml +43 -0
- gen_worker-0.1.0/examples/demo/uv.lock +1384 -0
- gen_worker-0.1.0/examples/e2e-stub/README.md +5 -0
- gen_worker-0.1.0/examples/e2e-stub/pyproject.toml +37 -0
- gen_worker-0.1.0/examples/e2e-stub/uv.lock +1286 -0
- gen_worker-0.1.0/examples/hello-world/README.md +53 -0
- gen_worker-0.1.0/examples/hello-world/pyproject.toml +41 -0
- gen_worker-0.1.0/examples/hello-world/uv.lock +1282 -0
- gen_worker-0.1.0/examples/image-gen/README.md +13 -0
- gen_worker-0.1.0/examples/image-gen/pyproject.toml +48 -0
- gen_worker-0.1.0/examples/image-gen/uv.lock +2832 -0
- gen_worker-0.1.0/examples/image-gen-legacy/README.md +12 -0
- gen_worker-0.1.0/examples/image-gen-legacy/pyproject.toml +37 -0
- gen_worker-0.1.0/examples/image-gen-legacy/uv.lock +2526 -0
- gen_worker-0.1.0/examples/medasr-transcribe/README.md +13 -0
- gen_worker-0.1.0/examples/medasr-transcribe/pyproject.toml +38 -0
- gen_worker-0.1.0/examples/medasr-transcribe/uv.lock +3177 -0
- gen_worker-0.1.0/examples/smoke-test/README.md +7 -0
- gen_worker-0.1.0/examples/smoke-test/pyproject.toml +38 -0
- gen_worker-0.1.0/examples/smoke-test/uv.lock +1440 -0
- gen_worker-0.1.0/examples/tiny-safetensors/README.md +30 -0
- gen_worker-0.1.0/examples/tiny-safetensors/pyproject.toml +36 -0
- gen_worker-0.1.0/examples/tiny-safetensors/uv.lock +2368 -0
- gen_worker-0.1.0/pyproject.toml +79 -0
- gen_worker-0.1.0/src/gen_worker/__init__.py +28 -0
- gen_worker-0.1.0/src/gen_worker/backends.py +26 -0
- gen_worker-0.1.0/src/gen_worker/decorators.py +74 -0
- gen_worker-0.1.0/src/gen_worker/default_model_manager/__init__.py +5 -0
- gen_worker-0.1.0/src/gen_worker/discover.py +368 -0
- gen_worker-0.1.0/src/gen_worker/downloader.py +84 -0
- gen_worker-0.1.0/src/gen_worker/entrypoint.py +163 -0
- gen_worker-0.1.0/src/gen_worker/errors.py +22 -0
- gen_worker-0.1.0/src/gen_worker/injection.py +135 -0
- gen_worker-0.1.0/src/gen_worker/model_interface.py +52 -0
- gen_worker-0.1.0/src/gen_worker/pb/__init__.py +27 -0
- gen_worker-0.1.0/src/gen_worker/pb/frontend_pb2.py +61 -0
- gen_worker-0.1.0/src/gen_worker/pb/frontend_pb2_grpc.py +233 -0
- gen_worker-0.1.0/src/gen_worker/pb/worker_scheduler_pb2.py +79 -0
- gen_worker-0.1.0/src/gen_worker/pb/worker_scheduler_pb2_grpc.py +100 -0
- gen_worker-0.1.0/src/gen_worker/project_validation.py +70 -0
- gen_worker-0.1.0/src/gen_worker/testing/__init__.py +1 -0
- gen_worker-0.1.0/src/gen_worker/testing/stub_manager.py +74 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/__init__.py +4 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/manager.py +2059 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/base_types/architecture.py +145 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/base_types/common.py +52 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/base_types/config.py +46 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/config.py +321 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/db/database.py +46 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/device.py +26 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/diffusers_fix.py +10 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/flashpack_loader.py +262 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/globals.py +59 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/load_models.py +238 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/local_cache.py +340 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/model_downloader.py +763 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/parse_cli.py +98 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/paths.py +22 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/repository.py +141 -0
- gen_worker-0.1.0/src/gen_worker/torch_manager/utils/utils.py +43 -0
- gen_worker-0.1.0/src/gen_worker/types.py +47 -0
- gen_worker-0.1.0/src/gen_worker/worker.py +2379 -0
- gen_worker-0.1.0/uv.lock +2290 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
**/.venv
|
|
3
|
+
*.pyc
|
|
4
|
+
__pycache__
|
|
5
|
+
**/dist
|
|
6
|
+
.mypy_cache
|
|
7
|
+
|
|
8
|
+
.env
|
|
9
|
+
generated_images/
|
|
10
|
+
|
|
11
|
+
!src/gen_worker/pb/**
|
|
12
|
+
!src/gen_worker/pb/__init__.py
|
|
13
|
+
|
|
14
|
+
# Keep generated protobuf stubs, but never commit bytecode caches.
|
|
15
|
+
src/gen_worker/pb/__pycache__/
|
|
16
|
+
src/gen_worker/pb/**/*.pyc
|
|
17
|
+
src/gen_worker/pb/**/*.pyo
|
|
18
|
+
|
|
19
|
+
**/*.png
|
|
20
|
+
**/*.jpg
|
|
21
|
+
|
|
22
|
+
.task/
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gen-worker
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A library used to build custom endpoints in Cozy Creator's serverless function platform.
|
|
5
|
+
Author-email: Paul Fidika <paul@fidika.com>
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: aiohttp>=3.11.14
|
|
8
|
+
Requires-Dist: backoff>=2.2.1
|
|
9
|
+
Requires-Dist: grpcio>=1.71.0
|
|
10
|
+
Requires-Dist: msgspec>=0.18.6
|
|
11
|
+
Requires-Dist: protobuf>=5.26.1
|
|
12
|
+
Requires-Dist: psutil>=7.0.0
|
|
13
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0
|
|
14
|
+
Requires-Dist: tqdm>=4.66.0
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: devpi-client>=7.2.0; extra == 'dev'
|
|
17
|
+
Requires-Dist: grpcio-tools>=1.71.0; extra == 'dev'
|
|
18
|
+
Provides-Extra: onnxruntime
|
|
19
|
+
Requires-Dist: onnxruntime>=1.18.0; extra == 'onnxruntime'
|
|
20
|
+
Provides-Extra: tensorrt
|
|
21
|
+
Requires-Dist: tensorrt; extra == 'tensorrt'
|
|
22
|
+
Provides-Extra: torch
|
|
23
|
+
Requires-Dist: flashpack>=0.1.2; extra == 'torch'
|
|
24
|
+
Requires-Dist: numpy>=1.26.0; extra == 'torch'
|
|
25
|
+
Requires-Dist: safetensors>=0.4.3; extra == 'torch'
|
|
26
|
+
Requires-Dist: torch>=2.6.0; extra == 'torch'
|
|
27
|
+
Requires-Dist: torchaudio>=2.6.0; extra == 'torch'
|
|
28
|
+
Requires-Dist: torchvision>=0.21.0; extra == 'torch'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
This is a python package, called gen_worker, which provides the worker runtime SDK:
|
|
32
|
+
|
|
33
|
+
- Orchestrator gRPC client + job loop
|
|
34
|
+
- Function discovery via @worker_function
|
|
35
|
+
- ActionContext + errors + progress events
|
|
36
|
+
- Model downloading from the Cozy hub (async + retries + progress)
|
|
37
|
+
- Output saving via the Cozy hub file API (ctx.save_bytes/ctx.save_file -> Asset refs)
|
|
38
|
+
|
|
39
|
+
Torch-based model memory management is optional and installed via extras.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
Files in `python-worker/src/gen_worker/pb` are generated from the `.proto` definitions in `gen-orchestrator/proto`.
|
|
44
|
+
|
|
45
|
+
Assuming `gen-orchestrator` is checked out as a sibling repo, regenerate stubs with:
|
|
46
|
+
|
|
47
|
+
`task -d python-worker proto`
|
|
48
|
+
|
|
49
|
+
This runs `uv sync --extra dev` and then `grpc_tools.protoc` against `../gen-orchestrator/proto`.
|
|
50
|
+
|
|
51
|
+
Install modes:
|
|
52
|
+
|
|
53
|
+
- Core only: `gen-worker`
|
|
54
|
+
- Torch runtime add-on: `gen-worker[torch]` (torch + torchvision + torchaudio + safetensors + flashpack + numpy)
|
|
55
|
+
|
|
56
|
+
Example tenant projects live in `./examples`. They use:
|
|
57
|
+
|
|
58
|
+
- `pyproject.toml` + `uv.lock` for dependencies (no requirements.txt)
|
|
59
|
+
- `[tool.cozy]` in `pyproject.toml` for deployment config (functions.modules, runtime.base_image, etc.)
|
|
60
|
+
|
|
61
|
+
Dependency policy:
|
|
62
|
+
|
|
63
|
+
- Require `pyproject.toml` and/or `uv.lock`
|
|
64
|
+
- Do not use `requirements.txt`
|
|
65
|
+
- Put Cozy deployment config in `pyproject.toml` under `[tool.cozy]`
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
|
|
69
|
+
```toml
|
|
70
|
+
[tool.cozy]
|
|
71
|
+
functions.modules = ["functions"]
|
|
72
|
+
|
|
73
|
+
[tool.cozy.runtime]
|
|
74
|
+
base_image = "ghcr.io/cozy/python-worker:cuda12.1-torch2.6"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Function signature:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from typing import Annotated, Iterator
|
|
81
|
+
|
|
82
|
+
import msgspec
|
|
83
|
+
|
|
84
|
+
from gen_worker import ActionContext, ResourceRequirements, worker_function
|
|
85
|
+
from gen_worker.injection import ModelArtifacts, ModelRef, ModelRefSource as Src
|
|
86
|
+
|
|
87
|
+
class Input(msgspec.Struct):
|
|
88
|
+
prompt: str
|
|
89
|
+
model_key: str = "default"
|
|
90
|
+
|
|
91
|
+
class Output(msgspec.Struct):
|
|
92
|
+
text: str
|
|
93
|
+
|
|
94
|
+
@worker_function(ResourceRequirements())
|
|
95
|
+
def run(
|
|
96
|
+
ctx: ActionContext,
|
|
97
|
+
# The worker injects cached handles based on the ModelRef.
|
|
98
|
+
# ModelRef(Src.DEPLOYMENT, ...) is fixed by deployment configuration (or a literal model id).
|
|
99
|
+
artifacts: Annotated[ModelArtifacts, ModelRef(Src.DEPLOYMENT, "google/functiongemma-270m-it")],
|
|
100
|
+
payload: Input,
|
|
101
|
+
) -> Output:
|
|
102
|
+
return Output(text=f"prompt={payload.prompt} model_root={artifacts.root_dir}")
|
|
103
|
+
|
|
104
|
+
class Delta(msgspec.Struct):
|
|
105
|
+
delta: str
|
|
106
|
+
|
|
107
|
+
@worker_function(ResourceRequirements())
|
|
108
|
+
def run_incremental(ctx: ActionContext, payload: Input) -> Iterator[Delta]:
|
|
109
|
+
for ch in payload.prompt:
|
|
110
|
+
if ctx.is_canceled():
|
|
111
|
+
raise InterruptedError("canceled")
|
|
112
|
+
yield Delta(delta=ch)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Dynamic checkpoints:
|
|
116
|
+
|
|
117
|
+
- Prefer deployment-defined allowlists. Requests pick a **key/label** from the payload
|
|
118
|
+
(e.g. `payload.model_key`), and the worker resolves it via a deployment-provided mapping.
|
|
119
|
+
- Use `ModelRef(Src.PAYLOAD, "model_key")` for this pattern (the payload value is a key, not a raw HF id).
|
|
120
|
+
|
|
121
|
+
Build contract (gen-builder):
|
|
122
|
+
|
|
123
|
+
- Tenant code + `pyproject.toml`/`uv.lock` are packaged together
|
|
124
|
+
- gen-builder layers tenant code + deps on top of a python-worker base image
|
|
125
|
+
- gen-orchestrator deploys the resulting worker image
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Manual builds (without gen-builder)
|
|
130
|
+
|
|
131
|
+
You can build worker images directly using Docker, without gen-builder.
|
|
132
|
+
|
|
133
|
+
### 1. Project structure
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
my-worker/
|
|
137
|
+
├── pyproject.toml # dependencies + [tool.cozy] config
|
|
138
|
+
├── uv.lock # lockfile (recommended)
|
|
139
|
+
└── src/
|
|
140
|
+
└── my_module/
|
|
141
|
+
└── __init__.py # contains @worker_function decorated functions
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 2. Copy the Dockerfile template
|
|
145
|
+
|
|
146
|
+
Copy `Dockerfile.template` from this repo to your project as `Dockerfile`:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
cp /path/to/python-worker/Dockerfile.template ./Dockerfile
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Or write your own:
|
|
153
|
+
|
|
154
|
+
```dockerfile
|
|
155
|
+
ARG BASE_IMAGE=cozycreator/python-worker:cuda12.8-torch2.9
|
|
156
|
+
FROM ${BASE_IMAGE}
|
|
157
|
+
|
|
158
|
+
WORKDIR /app
|
|
159
|
+
COPY . /app
|
|
160
|
+
|
|
161
|
+
RUN pip install --no-cache-dir uv
|
|
162
|
+
RUN if [ -f /app/uv.lock ]; then uv sync --frozen --no-dev; else uv sync --no-dev; fi
|
|
163
|
+
|
|
164
|
+
# Generate function manifest at build time
|
|
165
|
+
RUN mkdir -p /app/.cozy && python -m gen_worker.discover > /app/.cozy/manifest.json
|
|
166
|
+
|
|
167
|
+
ENTRYPOINT ["python", "-m", "gen_worker.entrypoint"]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 3. Build
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# CPU only
|
|
174
|
+
docker build -t my-worker --build-arg BASE_IMAGE=cozycreator/python-worker:cpu-torch2.9 .
|
|
175
|
+
|
|
176
|
+
# CUDA 12.8 (default)
|
|
177
|
+
docker build -t my-worker .
|
|
178
|
+
|
|
179
|
+
# CUDA 13.0
|
|
180
|
+
docker build -t my-worker --build-arg BASE_IMAGE=cozycreator/python-worker:cuda13-torch2.9 .
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 4. Run
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
docker run -e ORCHESTRATOR_URL=http://orchestrator:8080 my-worker
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The worker will:
|
|
190
|
+
1. Read the manifest from `/app/.cozy/manifest.json`
|
|
191
|
+
2. Self-register with the orchestrator
|
|
192
|
+
3. Start listening for tasks
|
|
193
|
+
|
|
194
|
+
### Available base images
|
|
195
|
+
|
|
196
|
+
| Image | GPU | CUDA | PyTorch |
|
|
197
|
+
|-------|-----|------|---------|
|
|
198
|
+
| `cozycreator/python-worker:cpu-torch2.9` | No | - | 2.9.1 |
|
|
199
|
+
| `cozycreator/python-worker:cuda12.6-torch2.9` | Yes | 12.6 | 2.9.1 |
|
|
200
|
+
| `cozycreator/python-worker:cuda12.8-torch2.9` | Yes | 12.8 | 2.9.1 |
|
|
201
|
+
| `cozycreator/python-worker:cuda13-torch2.9` | Yes | 13.0 | 2.9.1 |
|
|
202
|
+
|
|
203
|
+
### What happens automatically
|
|
204
|
+
|
|
205
|
+
- **Function discovery**: `gen_worker.discover` scans for `@worker_function` decorators
|
|
206
|
+
- **Manifest generation**: Input/output schemas extracted from msgspec types
|
|
207
|
+
- **Self-registration**: Worker registers its functions with orchestrator on startup
|
|
208
|
+
|
|
209
|
+
No gen-builder required for local development or custom CI pipelines.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
Env hints:
|
|
214
|
+
|
|
215
|
+
- `SCHEDULER_ADDR` sets the primary scheduler address.
|
|
216
|
+
- `SCHEDULER_ADDRS` (comma-separated) provides seed addresses for leader discovery.
|
|
217
|
+
- `WORKER_JWT` is accepted as the auth token if `AUTH_TOKEN` is not set.
|
|
218
|
+
- `SCHEDULER_JWKS_URL` enables verification of `WORKER_JWT` before connecting.
|
|
219
|
+
- JWT verification uses RSA and requires PyJWT crypto support (installed by default via `PyJWT[crypto]`).
|
|
220
|
+
- `WORKER_MAX_INPUT_BYTES`, `WORKER_MAX_OUTPUT_BYTES`, `WORKER_MAX_UPLOAD_BYTES` cap payload sizes.
|
|
221
|
+
- `WORKER_MAX_CONCURRENCY` limits concurrent runs; `ResourceRequirements(max_concurrency=...)` limits per-function.
|
|
222
|
+
- `COZY_HUB_URL` base URL for Cozy hub downloads (used by core downloader).
|
|
223
|
+
- `COZY_HUB_TOKEN` optional bearer token for Cozy hub downloads.
|
|
224
|
+
- `MODEL_MANAGER_CLASS` optional ModelManager plugin (module:Class) loaded at startup.
|
|
225
|
+
|
|
226
|
+
Error hints:
|
|
227
|
+
|
|
228
|
+
- Use `gen_worker.errors.RetryableError` in worker functions to flag retryable failures.
|
|
229
|
+
|
|
230
|
+
API note:
|
|
231
|
+
|
|
232
|
+
- `output_format` is an orchestrator HTTP response preference (queue vs long-poll bytes/url) and does not change worker behavior; workers persist outputs as `Asset` refs via the Cozy hub file API.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
This is a python package, called gen_worker, which provides the worker runtime SDK:
|
|
2
|
+
|
|
3
|
+
- Orchestrator gRPC client + job loop
|
|
4
|
+
- Function discovery via @worker_function
|
|
5
|
+
- ActionContext + errors + progress events
|
|
6
|
+
- Model downloading from the Cozy hub (async + retries + progress)
|
|
7
|
+
- Output saving via the Cozy hub file API (ctx.save_bytes/ctx.save_file -> Asset refs)
|
|
8
|
+
|
|
9
|
+
Torch-based model memory management is optional and installed via extras.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Files in `python-worker/src/gen_worker/pb` are generated from the `.proto` definitions in `gen-orchestrator/proto`.
|
|
14
|
+
|
|
15
|
+
Assuming `gen-orchestrator` is checked out as a sibling repo, regenerate stubs with:
|
|
16
|
+
|
|
17
|
+
`task -d python-worker proto`
|
|
18
|
+
|
|
19
|
+
This runs `uv sync --extra dev` and then `grpc_tools.protoc` against `../gen-orchestrator/proto`.
|
|
20
|
+
|
|
21
|
+
Install modes:
|
|
22
|
+
|
|
23
|
+
- Core only: `gen-worker`
|
|
24
|
+
- Torch runtime add-on: `gen-worker[torch]` (torch + torchvision + torchaudio + safetensors + flashpack + numpy)
|
|
25
|
+
|
|
26
|
+
Example tenant projects live in `./examples`. They use:
|
|
27
|
+
|
|
28
|
+
- `pyproject.toml` + `uv.lock` for dependencies (no requirements.txt)
|
|
29
|
+
- `[tool.cozy]` in `pyproject.toml` for deployment config (functions.modules, runtime.base_image, etc.)
|
|
30
|
+
|
|
31
|
+
Dependency policy:
|
|
32
|
+
|
|
33
|
+
- Require `pyproject.toml` and/or `uv.lock`
|
|
34
|
+
- Do not use `requirements.txt`
|
|
35
|
+
- Put Cozy deployment config in `pyproject.toml` under `[tool.cozy]`
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
|
|
39
|
+
```toml
|
|
40
|
+
[tool.cozy]
|
|
41
|
+
functions.modules = ["functions"]
|
|
42
|
+
|
|
43
|
+
[tool.cozy.runtime]
|
|
44
|
+
base_image = "ghcr.io/cozy/python-worker:cuda12.1-torch2.6"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Function signature:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from typing import Annotated, Iterator
|
|
51
|
+
|
|
52
|
+
import msgspec
|
|
53
|
+
|
|
54
|
+
from gen_worker import ActionContext, ResourceRequirements, worker_function
|
|
55
|
+
from gen_worker.injection import ModelArtifacts, ModelRef, ModelRefSource as Src
|
|
56
|
+
|
|
57
|
+
class Input(msgspec.Struct):
|
|
58
|
+
prompt: str
|
|
59
|
+
model_key: str = "default"
|
|
60
|
+
|
|
61
|
+
class Output(msgspec.Struct):
|
|
62
|
+
text: str
|
|
63
|
+
|
|
64
|
+
@worker_function(ResourceRequirements())
|
|
65
|
+
def run(
|
|
66
|
+
ctx: ActionContext,
|
|
67
|
+
# The worker injects cached handles based on the ModelRef.
|
|
68
|
+
# ModelRef(Src.DEPLOYMENT, ...) is fixed by deployment configuration (or a literal model id).
|
|
69
|
+
artifacts: Annotated[ModelArtifacts, ModelRef(Src.DEPLOYMENT, "google/functiongemma-270m-it")],
|
|
70
|
+
payload: Input,
|
|
71
|
+
) -> Output:
|
|
72
|
+
return Output(text=f"prompt={payload.prompt} model_root={artifacts.root_dir}")
|
|
73
|
+
|
|
74
|
+
class Delta(msgspec.Struct):
|
|
75
|
+
delta: str
|
|
76
|
+
|
|
77
|
+
@worker_function(ResourceRequirements())
|
|
78
|
+
def run_incremental(ctx: ActionContext, payload: Input) -> Iterator[Delta]:
|
|
79
|
+
for ch in payload.prompt:
|
|
80
|
+
if ctx.is_canceled():
|
|
81
|
+
raise InterruptedError("canceled")
|
|
82
|
+
yield Delta(delta=ch)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Dynamic checkpoints:
|
|
86
|
+
|
|
87
|
+
- Prefer deployment-defined allowlists. Requests pick a **key/label** from the payload
|
|
88
|
+
(e.g. `payload.model_key`), and the worker resolves it via a deployment-provided mapping.
|
|
89
|
+
- Use `ModelRef(Src.PAYLOAD, "model_key")` for this pattern (the payload value is a key, not a raw HF id).
|
|
90
|
+
|
|
91
|
+
Build contract (gen-builder):
|
|
92
|
+
|
|
93
|
+
- Tenant code + `pyproject.toml`/`uv.lock` are packaged together
|
|
94
|
+
- gen-builder layers tenant code + deps on top of a python-worker base image
|
|
95
|
+
- gen-orchestrator deploys the resulting worker image
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Manual builds (without gen-builder)
|
|
100
|
+
|
|
101
|
+
You can build worker images directly using Docker, without gen-builder.
|
|
102
|
+
|
|
103
|
+
### 1. Project structure
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
my-worker/
|
|
107
|
+
├── pyproject.toml # dependencies + [tool.cozy] config
|
|
108
|
+
├── uv.lock # lockfile (recommended)
|
|
109
|
+
└── src/
|
|
110
|
+
└── my_module/
|
|
111
|
+
└── __init__.py # contains @worker_function decorated functions
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 2. Copy the Dockerfile template
|
|
115
|
+
|
|
116
|
+
Copy `Dockerfile.template` from this repo to your project as `Dockerfile`:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
cp /path/to/python-worker/Dockerfile.template ./Dockerfile
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Or write your own:
|
|
123
|
+
|
|
124
|
+
```dockerfile
|
|
125
|
+
ARG BASE_IMAGE=cozycreator/python-worker:cuda12.8-torch2.9
|
|
126
|
+
FROM ${BASE_IMAGE}
|
|
127
|
+
|
|
128
|
+
WORKDIR /app
|
|
129
|
+
COPY . /app
|
|
130
|
+
|
|
131
|
+
RUN pip install --no-cache-dir uv
|
|
132
|
+
RUN if [ -f /app/uv.lock ]; then uv sync --frozen --no-dev; else uv sync --no-dev; fi
|
|
133
|
+
|
|
134
|
+
# Generate function manifest at build time
|
|
135
|
+
RUN mkdir -p /app/.cozy && python -m gen_worker.discover > /app/.cozy/manifest.json
|
|
136
|
+
|
|
137
|
+
ENTRYPOINT ["python", "-m", "gen_worker.entrypoint"]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 3. Build
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# CPU only
|
|
144
|
+
docker build -t my-worker --build-arg BASE_IMAGE=cozycreator/python-worker:cpu-torch2.9 .
|
|
145
|
+
|
|
146
|
+
# CUDA 12.8 (default)
|
|
147
|
+
docker build -t my-worker .
|
|
148
|
+
|
|
149
|
+
# CUDA 13.0
|
|
150
|
+
docker build -t my-worker --build-arg BASE_IMAGE=cozycreator/python-worker:cuda13-torch2.9 .
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 4. Run
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
docker run -e ORCHESTRATOR_URL=http://orchestrator:8080 my-worker
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The worker will:
|
|
160
|
+
1. Read the manifest from `/app/.cozy/manifest.json`
|
|
161
|
+
2. Self-register with the orchestrator
|
|
162
|
+
3. Start listening for tasks
|
|
163
|
+
|
|
164
|
+
### Available base images
|
|
165
|
+
|
|
166
|
+
| Image | GPU | CUDA | PyTorch |
|
|
167
|
+
|-------|-----|------|---------|
|
|
168
|
+
| `cozycreator/python-worker:cpu-torch2.9` | No | - | 2.9.1 |
|
|
169
|
+
| `cozycreator/python-worker:cuda12.6-torch2.9` | Yes | 12.6 | 2.9.1 |
|
|
170
|
+
| `cozycreator/python-worker:cuda12.8-torch2.9` | Yes | 12.8 | 2.9.1 |
|
|
171
|
+
| `cozycreator/python-worker:cuda13-torch2.9` | Yes | 13.0 | 2.9.1 |
|
|
172
|
+
|
|
173
|
+
### What happens automatically
|
|
174
|
+
|
|
175
|
+
- **Function discovery**: `gen_worker.discover` scans for `@worker_function` decorators
|
|
176
|
+
- **Manifest generation**: Input/output schemas extracted from msgspec types
|
|
177
|
+
- **Self-registration**: Worker registers its functions with orchestrator on startup
|
|
178
|
+
|
|
179
|
+
No gen-builder required for local development or custom CI pipelines.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
Env hints:
|
|
184
|
+
|
|
185
|
+
- `SCHEDULER_ADDR` sets the primary scheduler address.
|
|
186
|
+
- `SCHEDULER_ADDRS` (comma-separated) provides seed addresses for leader discovery.
|
|
187
|
+
- `WORKER_JWT` is accepted as the auth token if `AUTH_TOKEN` is not set.
|
|
188
|
+
- `SCHEDULER_JWKS_URL` enables verification of `WORKER_JWT` before connecting.
|
|
189
|
+
- JWT verification uses RSA and requires PyJWT crypto support (installed by default via `PyJWT[crypto]`).
|
|
190
|
+
- `WORKER_MAX_INPUT_BYTES`, `WORKER_MAX_OUTPUT_BYTES`, `WORKER_MAX_UPLOAD_BYTES` cap payload sizes.
|
|
191
|
+
- `WORKER_MAX_CONCURRENCY` limits concurrent runs; `ResourceRequirements(max_concurrency=...)` limits per-function.
|
|
192
|
+
- `COZY_HUB_URL` base URL for Cozy hub downloads (used by core downloader).
|
|
193
|
+
- `COZY_HUB_TOKEN` optional bearer token for Cozy hub downloads.
|
|
194
|
+
- `MODEL_MANAGER_CLASS` optional ModelManager plugin (module:Class) loaded at startup.
|
|
195
|
+
|
|
196
|
+
Error hints:
|
|
197
|
+
|
|
198
|
+
- Use `gen_worker.errors.RetryableError` in worker functions to flag retryable failures.
|
|
199
|
+
|
|
200
|
+
API note:
|
|
201
|
+
|
|
202
|
+
- `output_format` is an orchestrator HTTP response preference (queue vs long-poll bytes/url) and does not change worker behavior; workers persist outputs as `Asset` refs via the Cozy hub file API.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Demo worker functions (minimal).
|
|
2
|
+
|
|
3
|
+
What this contains:
|
|
4
|
+
|
|
5
|
+
- Python module `demo` with several @worker_function examples.
|
|
6
|
+
- `pyproject.toml` with deps and `[tool.cozy]` deployment config.
|
|
7
|
+
|
|
8
|
+
Notes:
|
|
9
|
+
|
|
10
|
+
- Install deps with `uv sync` and generate `uv.lock` for reproducible builds.
|
|
11
|
+
- gen-builder reads `[tool.cozy].functions.modules` from `pyproject.toml`.
|
|
12
|
+
- Deploy with gen-builder by pointing the build source at this folder.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "demo"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Paul Fidika", email = "paul@fidika.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"gen-worker>=0.1.4",
|
|
12
|
+
"Pillow>=10.0",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[dependency-groups]
|
|
16
|
+
dev = [
|
|
17
|
+
"mypy>=1.10.0",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.scripts]
|
|
21
|
+
demo = "demo:main"
|
|
22
|
+
|
|
23
|
+
[build-system]
|
|
24
|
+
requires = ["hatchling"]
|
|
25
|
+
build-backend = "hatchling.build"
|
|
26
|
+
|
|
27
|
+
[tool.hatch.metadata]
|
|
28
|
+
allow-direct-references = true
|
|
29
|
+
|
|
30
|
+
[tool.hatch.build.targets.wheel]
|
|
31
|
+
packages = ["src/demo"]
|
|
32
|
+
|
|
33
|
+
[tool.uv.sources]
|
|
34
|
+
gen-worker = { path = "../.." }
|
|
35
|
+
|
|
36
|
+
[tool.mypy]
|
|
37
|
+
python_version = "3.12"
|
|
38
|
+
ignore_missing_imports = true
|
|
39
|
+
disallow_untyped_defs = true
|
|
40
|
+
python_executable = ".venv/bin/python3"
|
|
41
|
+
|
|
42
|
+
[tool.cozy.runtime]
|
|
43
|
+
base_image = "ghcr.io/cozy/python-worker:cuda12.1-torch2.6"
|