feat: refresh VFS
This commit is contained in:
@@ -44,3 +44,10 @@ RUSTFS_VERSION_BUCKET=versions
|
|||||||
RUSTFS_RUN_LOG_BUCKET=run-logs
|
RUSTFS_RUN_LOG_BUCKET=run-logs
|
||||||
RUSTFS_TRASH_BUCKET=trash
|
RUSTFS_TRASH_BUCKET=trash
|
||||||
RUSTFS_TRASH_RETENTION_DAYS=30
|
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
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from backend.auth import router as auth_router
|
|||||||
from backend.jupyter import router as jupyter_router
|
from backend.jupyter import router as jupyter_router
|
||||||
from backend.resources import router as resources_router
|
from backend.resources import router as resources_router
|
||||||
from backend.runtime_client import RuntimeClient
|
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.schedule_runs import router as schedule_runs_router
|
||||||
from backend.schedules import router as schedules_router
|
from backend.schedules import router as schedules_router
|
||||||
from backend.scripts import router as scripts_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),
|
timeout=httpx.Timeout(30.0),
|
||||||
)
|
)
|
||||||
app.state.runtime_client = RuntimeClient(runtime_http_client)
|
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:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
|
await rclone_http_client.aclose()
|
||||||
await runtime_http_client.aclose()
|
await runtime_http_client.aclose()
|
||||||
await storage_http_client.aclose()
|
await storage_http_client.aclose()
|
||||||
await engine.dispose()
|
await engine.dispose()
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from typing import Any
|
|||||||
|
|
||||||
from fastapi import (
|
from fastapi import (
|
||||||
APIRouter,
|
APIRouter,
|
||||||
|
BackgroundTasks,
|
||||||
Depends,
|
Depends,
|
||||||
Header,
|
Header,
|
||||||
HTTPException,
|
HTTPException,
|
||||||
@@ -344,6 +345,7 @@ async def create_script_record(
|
|||||||
async def create_script(
|
async def create_script(
|
||||||
payload: CreateScriptRequest,
|
payload: CreateScriptRequest,
|
||||||
request: Request,
|
request: Request,
|
||||||
|
background_tasks: BackgroundTasks,
|
||||||
context: RequestContext = Depends(request_context),
|
context: RequestContext = Depends(request_context),
|
||||||
session: AsyncSession = Depends(database_session),
|
session: AsyncSession = Depends(database_session),
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
@@ -359,6 +361,11 @@ async def create_script(
|
|||||||
context=context,
|
context=context,
|
||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
|
background_tasks.add_task(
|
||||||
|
request.app.state.rclone_rc_client.vfs_refresh,
|
||||||
|
dir_path=context.workspace.workspace_id,
|
||||||
|
recursive=True,
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"request_id": context.request_id,
|
"request_id": context.request_id,
|
||||||
"data": script_payload(script, storage_data),
|
"data": script_payload(script, storage_data),
|
||||||
@@ -372,6 +379,7 @@ async def create_script(
|
|||||||
)
|
)
|
||||||
async def upload_script(
|
async def upload_script(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
background_tasks: BackgroundTasks,
|
||||||
file_name: str = Query(min_length=1, max_length=255),
|
file_name: str = Query(min_length=1, max_length=255),
|
||||||
parent_path: str = Query(default="", max_length=1024),
|
parent_path: str = Query(default="", max_length=1024),
|
||||||
visibility: str = Query(
|
visibility: str = Query(
|
||||||
@@ -413,6 +421,11 @@ async def upload_script(
|
|||||||
context=context,
|
context=context,
|
||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
|
background_tasks.add_task(
|
||||||
|
request.app.state.rclone_rc_client.vfs_refresh,
|
||||||
|
dir_path=context.workspace.workspace_id,
|
||||||
|
recursive=True,
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"request_id": context.request_id,
|
"request_id": context.request_id,
|
||||||
"data": script_payload(script, storage_data),
|
"data": script_payload(script, storage_data),
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ class Settings(BaseSettings):
|
|||||||
default="http://runtime:8000",
|
default="http://runtime:8000",
|
||||||
description="Backend → Runtime HTTP endpoint.",
|
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 object storage ────────────────────────────────────
|
||||||
rustfs_endpoint: str = Field(
|
rustfs_endpoint: str = Field(
|
||||||
|
|||||||
Reference in New Issue
Block a user