Spaces:
Running
Running
Download start.py from Shoraky/Sporalize-api: direct link, hf CLI and curl.
- Browser
- Download file 2.94 kB
-
https://huggingface.co/spaces/Shoraky/Sporalize-api/resolve/main/start.py
- Command line
-
hf download hf://spaces/Shoraky/Sporalize-api/start.py
-
curl -L -o start.py https://huggingface.co/spaces/Shoraky/Sporalize-api/resolve/main/start.py
2.94 kB
| """Run the public Node API and private Python worker as one service.""" | |
| import json | |
| import os | |
| from pathlib import Path | |
| import signal | |
| import subprocess | |
| import sys | |
| import time | |
| from urllib.request import urlopen | |
| from dotenv import load_dotenv | |
| def wait_for_analysis(process, should_stop, timeout_seconds=25 * 60): | |
| deadline = time.monotonic() + timeout_seconds | |
| while not should_stop(): | |
| exit_code = process.poll() | |
| if exit_code is not None: | |
| print(f"Analysis process exited before it was ready ({exit_code})", flush=True) | |
| return False | |
| try: | |
| with urlopen("http://127.0.0.1:8000/healthz", timeout=1) as response: | |
| payload = json.load(response) if response.status == 200 else None | |
| if isinstance(payload, dict) and payload.get("ok") is True: | |
| return process.poll() is None | |
| except (OSError, ValueError): | |
| pass | |
| if time.monotonic() >= deadline: | |
| print(f"Analysis process did not become ready within {timeout_seconds} seconds", flush=True) | |
| return False | |
| time.sleep(0.5) | |
| return False | |
| def main(): | |
| root = Path(__file__).resolve().parent | |
| load_dotenv(root / ".env") | |
| port = int(os.environ.get("PORT", "4000")) | |
| if not 1 <= port <= 65535 or port == 8000: | |
| raise ValueError("PORT must be between 1 and 65535 and differ from AI port 8000") | |
| env = dict(os.environ, PORT=str(port), | |
| ANALYSIS_API_URL="http://127.0.0.1:8000", | |
| BACKEND_INTERNAL_URL=f"http://127.0.0.1:{port}") | |
| children = [] | |
| stopping = False | |
| def stop(signum, frame): | |
| nonlocal stopping | |
| stopping = True | |
| for sig in (signal.SIGINT, signal.SIGTERM): | |
| signal.signal(sig, stop) | |
| try: | |
| analysis = subprocess.Popen([sys.executable, "-m", "uvicorn", "app:app", | |
| "--host", "127.0.0.1", "--port", "8000", "--workers", "1"], cwd=root, env=env) | |
| children.append(analysis) | |
| if not wait_for_analysis(analysis, lambda: stopping): | |
| return 0 if stopping else 1 | |
| children.append(subprocess.Popen(["node", "dist/server.js"], cwd=root, env=env)) | |
| while not stopping: | |
| for child in children: | |
| if child.poll() is not None: | |
| print(f"Backend process {child.pid} exited ({child.returncode}); stopping service", flush=True) | |
| return child.returncode or 1 | |
| time.sleep(0.25) | |
| return 0 | |
| finally: | |
| for child in children: | |
| if child.poll() is None: | |
| child.terminate() | |
| deadline = time.monotonic() + 15 | |
| for child in children: | |
| try: | |
| child.wait(timeout=max(0, deadline - time.monotonic())) | |
| except subprocess.TimeoutExpired: | |
| child.kill() | |
| child.wait() | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |