Add minimal strategy demo

This commit is contained in:
Codex
2026-06-03 23:39:27 +08:00
commit 312c1860e8
5 changed files with 145 additions and 0 deletions

4
.dockerignore Normal file
View File

@@ -0,0 +1,4 @@
.git
__pycache__/
*.pyc
.pytest_cache/

21
Dockerfile Normal file
View File

@@ -0,0 +1,21 @@
FROM python:3.11-slim
ARG TASK_TYPE
ARG GPU_TYPE
ARG FRAMEWORK
ENV TASK_TYPE=${TASK_TYPE}
ENV GPU_TYPE=${GPU_TYPE}
ENV FRAMEWORK=${FRAMEWORK}
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
CMD ["python", "main.py"]

46
README.md Normal file
View File

@@ -0,0 +1,46 @@
# Strategy Platform Demo Repo
Minimal strategy repository for testing the platform Kaniko build and deployment flow.
It satisfies the runtime contract from the parent README:
- Root-level `Dockerfile`
- Listens on port `8080`
- Exposes `GET /health`
- Reads `TASK_TYPE`, `GPU_TYPE`, `FRAMEWORK`, and `EXTERNAL_SERVICE_TOKEN`
- Handles `SIGTERM` for graceful shutdown
## Local Run
```bash
python main.py
curl http://localhost:8080/health
curl http://localhost:8080/
```
## Build Locally
```bash
docker build \
--build-arg TASK_TYPE=validation \
--build-arg GPU_TYPE=amd64 \
--build-arg FRAMEWORK=pytorch \
-t strategy-demo:v1.0.0 .
docker run --rm -p 8080:8080 strategy-demo:v1.0.0
```
## Platform Test
Push this directory to Gitea and keep the `v1.0.0` tag. Then create a strategy with:
```json
{
"name": "strategy-demo",
"repo_url": "https://<your-gitea-host>/<user>/strategy-demo",
"tag": "v1.0.0",
"task_type": "validation",
"gpu_type": "amd64",
"framework": "pytorch"
}
```

73
main.py Normal file
View File

@@ -0,0 +1,73 @@
import json
import os
import signal
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
HOST = "0.0.0.0"
PORT = 8080
shutdown_requested = False
def _config() -> dict:
token = os.getenv("EXTERNAL_SERVICE_TOKEN", "")
return {
"task_type": os.getenv("TASK_TYPE", ""),
"gpu_type": os.getenv("GPU_TYPE", ""),
"framework": os.getenv("FRAMEWORK", ""),
"external_service_token_present": bool(token),
}
class Handler(BaseHTTPRequestHandler):
def do_GET(self) -> None:
if self.path == "/health":
self._send_json({"status": "ok"})
return
if self.path == "/":
self._send_json(
{
"name": "strategy-demo",
"status": "running",
"config": _config(),
}
)
return
self._send_json({"error": "not found"}, status=404)
def log_message(self, fmt: str, *args: object) -> None:
print(f"{self.address_string()} - {fmt % args}", flush=True)
def _send_json(self, body: dict, status: int = 200) -> None:
payload = json.dumps(body).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(payload)))
self.end_headers()
self.wfile.write(payload)
def _handle_signal(signum: int, _frame: object) -> None:
global shutdown_requested
shutdown_requested = True
print(f"received signal {signum}, shutting down", flush=True)
def main() -> None:
signal.signal(signal.SIGTERM, _handle_signal)
signal.signal(signal.SIGINT, _handle_signal)
server = ThreadingHTTPServer((HOST, PORT), Handler)
server.timeout = 1
print(f"strategy-demo listening on {HOST}:{PORT}", flush=True)
while not shutdown_requested:
server.handle_request()
server.server_close()
if __name__ == "__main__":
main()

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@