feat: refresh VFS

This commit is contained in:
tao.chen
2026-08-03 20:23:18 +08:00
parent e1172a0091
commit 134f8ca552
4 changed files with 32 additions and 0 deletions
+7
View File
@@ -44,3 +44,10 @@ RUSTFS_VERSION_BUCKET=versions
RUSTFS_RUN_LOG_BUCKET=run-logs
RUSTFS_TRASH_BUCKET=trash
RUSTFS_TRASH_RETENTION_DAYS=30
# rclone RC (HTTP control API). The runtime container starts rclone with
# `--rc --rc-addr 0.0.0.0:5572 --rc-no-auth` (see runtime/src/runtime/mount.py),
# so the backend can POST /vfs/refresh here to invalidate the FUSE dir-cache
# after writing new workspace files. Default points at the runtime service
# over the compose network.
RCLONE_RC_URL=http://runtime:5572
+8
View File
@@ -16,6 +16,7 @@ from backend.auth import router as auth_router
from backend.jupyter import router as jupyter_router
from backend.resources import router as resources_router
from backend.runtime_client import RuntimeClient
from backend.rclone_rc_client import RcloneRCClient
from backend.schedule_runs import router as schedule_runs_router
from backend.schedules import router as schedules_router
from backend.scripts import router as scripts_router
@@ -59,9 +60,16 @@ async def lifespan(app: Any) -> AsyncIterator[None]:
timeout=httpx.Timeout(30.0),
)
app.state.runtime_client = RuntimeClient(runtime_http_client)
# Short timeout — refresh is best-effort and runs in a BackgroundTask.
rclone_http_client = httpx.AsyncClient(
base_url=settings.rclone_rc_url,
timeout=httpx.Timeout(30.0),
)
app.state.rclone_rc_client = RcloneRCClient(rclone_http_client)
try:
yield
finally:
await rclone_http_client.aclose()
await runtime_http_client.aclose()
await storage_http_client.aclose()
await engine.dispose()
+13
View File
@@ -10,6 +10,7 @@ from typing import Any
from fastapi import (
APIRouter,
BackgroundTasks,
Depends,
Header,
HTTPException,
@@ -344,6 +345,7 @@ async def create_script_record(
async def create_script(
payload: CreateScriptRequest,
request: Request,
background_tasks: BackgroundTasks,
context: RequestContext = Depends(request_context),
session: AsyncSession = Depends(database_session),
) -> dict[str, Any]:
@@ -359,6 +361,11 @@ async def create_script(
context=context,
session=session,
)
background_tasks.add_task(
request.app.state.rclone_rc_client.vfs_refresh,
dir_path=context.workspace.workspace_id,
recursive=True,
)
return {
"request_id": context.request_id,
"data": script_payload(script, storage_data),
@@ -372,6 +379,7 @@ async def create_script(
)
async def upload_script(
request: Request,
background_tasks: BackgroundTasks,
file_name: str = Query(min_length=1, max_length=255),
parent_path: str = Query(default="", max_length=1024),
visibility: str = Query(
@@ -413,6 +421,11 @@ async def upload_script(
context=context,
session=session,
)
background_tasks.add_task(
request.app.state.rclone_rc_client.vfs_refresh,
dir_path=context.workspace.workspace_id,
recursive=True,
)
return {
"request_id": context.request_id,
"data": script_payload(script, storage_data),
+4
View File
@@ -54,6 +54,10 @@ class Settings(BaseSettings):
default="http://runtime:8000",
description="Backend → Runtime HTTP endpoint.",
)
rclone_rc_url: str = Field(
default="http://runtime:5572",
description="Backend → rclone RC HTTP endpoint (VFS cache invalidation).",
)
# ── RustFS object storage ────────────────────────────────────
rustfs_endpoint: str = Field(