Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion Dockerfile.cloud
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
FROM nvidia/cuda:12.8.0-cudnn-runtime-ubuntu24.04
# Use the plain `runtime` variant (no cuDNN). pyproject.toml overrides
# `nvidia-cudnn-cu12>=9.15` so cuDNN ships in the venv anyway, and the
# base copy was dead weight (~700 MB).
FROM nvidia/cuda:12.8.0-runtime-ubuntu24.04

ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1
Expand Down Expand Up @@ -45,11 +48,31 @@ RUN uv python install && \
# Copy project files
COPY src/ /app/src/

# Pre-build the venv with the runtime extras the cloud wrapper invokes
# (`uv run --extra livepeer --extra kafka livepeer-runner`). Without this
# the first cold start has to fetch + install aiokafka, uvicorn[standard],
# and re-resolve the entire dep graph at runtime — adds ~10s per cold start.
RUN uv sync --extra livepeer --extra kafka --no-dev

# Pre-install bundled plugins (cannot be removed by users)
ENV DAYDREAM_SCOPE_BUNDLED_PLUGINS_FILE="/app/bundled-plugins.txt"
RUN echo "git+https://github.com/daydreamlive/scope-ltx-2.git@d13b5f9d94130b975989cd820eedbef5b3a8f165" > /app/bundled-plugins.txt
RUN uv run daydream-scope install git+https://github.com/daydreamlive/scope-ltx-2.git@d13b5f9d94130b975989cd820eedbef5b3a8f165

# Strip never-at-runtime files from the venv to shrink the image.
# Keep .pyc/__pycache__ so first import isn't slowed by recompilation.
# Drop C/C++ headers/sources (only used at compile time), package
# tests/ and docs/ directories, .pdb debug symbols, and the uv/apt
# caches we don't need at runtime. Keep examples/ — some packages
# import from it.
RUN find /app/.venv -depth -type d \
\( -name 'tests' -o -name 'test' -o -name 'doc' -o -name 'docs' \) \
-exec rm -rf {} + 2>/dev/null || true && \
find /app/.venv -type f \
\( -name '*.h' -o -name '*.c' -o -name '*.cpp' -o -name '*.hpp' -o -name '*.pdb' \) \
-delete 2>/dev/null || true && \
rm -rf /tmp/uv-cache /root/.cache /var/cache/apt/archives/*.deb

# Expose port 8000 for RunPod HTTP proxy
EXPOSE 8000

Expand Down
7 changes: 7 additions & 0 deletions src/scope/cloud/livepeer_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ async def lifespan(_app: FastAPI):
"""Initialize embedded Scope app lifespan and ASGI client."""
global scope_client
async with scope_lifespan(scope_app):
# Pre-warm the pipeline registry so the import cascade
# (torch / diffusers / transformers / torchao / per-pipeline modules)
# runs at runner startup instead of on the first cloud-proxy request.
# Shaves the registry-init delay out of the user-perceived connect path.
import scope.core.pipelines.registry # noqa: F401

scope_client = httpx.AsyncClient(
transport=httpx.ASGITransport(app=scope_app),
base_url="http://runner",
Expand Down Expand Up @@ -1546,6 +1552,7 @@ async def websocket_endpoint(ws: WebSocket) -> None:
if control_task is not None:
await _shutdown_task(control_task, task_name="control_channel")
_connection_active = False
logger.info("XXX: WebSocket client disconnected")
set_connection_id(None)


Expand Down
13 changes: 13 additions & 0 deletions src/scope/cloud/livepeer_fal_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,17 @@ def _get_git_sha() -> str:

GIT_SHA = _get_git_sha()
DOCKER_IMAGE = f"daydreamlive/scope:{GIT_SHA}"
# Re-sync after COPY so the daydream-scope editable install picks up the
# freshly-copied src/ at image build time. Without this, the first `uv run`
# at cold start sees a stale path source and rebuilds + reinstalls the
# project (the ~10s "Built daydream-scope @ file:///app" + Uninstalled/Installed
# block visible in cold-start logs).
dockerfile_str = f"""
FROM {DOCKER_IMAGE}
WORKDIR /app
COPY pyproject.toml uv.lock README.md patches.pth /app/
COPY src/ /app/src/
RUN uv sync --extra livepeer --extra kafka --no-dev
"""
custom_image = ContainerImage.from_dockerfile_str(
dockerfile_str,
Expand Down Expand Up @@ -386,6 +392,13 @@ class LivepeerScopeApp(fal.App, keep_alive=300):

image = custom_image
machine_type = "GPU-H100"
# These are required in fal isolate's runtime context (separate from
# the image's /app/.venv), where the App's setup() and websocket
# handler actually run. They're cheap — the real cold-start savings
# come from the image-level `uv sync --extra livepeer --extra kafka`
# in Dockerfile.cloud and the fal-side dockerfile_str re-sync, which
# together skip the ~10s `uv run --extra` resync that previously fired
# when the wrapper invoked `livepeer-runner`.
requirements = [
"websockets",
"httpx",
Expand Down
Loading