feat(scheduler,rotation,envelope,api,ui): pgqueuer jobs and deferred injects, master rotation with handout, vault envelope, jobs page
This commit is contained in:
@@ -60,6 +60,7 @@ if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
from beaver_gateway.core.conversations import Conversations
|
||||
from beaver_gateway.core.scheduler import Scheduler
|
||||
from beaver_gateway.frontends.base import GatewayRuntime
|
||||
|
||||
_log = logging.getLogger("beaver_gateway.frontends.api")
|
||||
@@ -525,19 +526,48 @@ def build_app(runtime: GatewayRuntime, *, memory_root: Path | None = None) -> Fa
|
||||
await require_token(request, runtime, scope=SCOPE)
|
||||
raw = request.query_params.get("conversation")
|
||||
conv = await conv_of(raw) if raw else None
|
||||
return {
|
||||
"schedules": [
|
||||
{
|
||||
"id": s.id,
|
||||
"conversation_row": s.conversation_id,
|
||||
"execute_at": _iso(s.execute_at),
|
||||
"text": s.text,
|
||||
"created_at": _iso(s.created_at),
|
||||
"delivered_at": _iso(s.delivered_at),
|
||||
}
|
||||
for s in await conversations.schedules(conv)
|
||||
]
|
||||
}
|
||||
return {"schedules": await conversations.schedules(conv)}
|
||||
|
||||
def scheduler_of() -> Scheduler:
|
||||
if runtime.scheduler is None:
|
||||
raise HTTPException(status.HTTP_503_SERVICE_UNAVAILABLE, "no scheduler")
|
||||
return cast("Scheduler", runtime.scheduler)
|
||||
|
||||
@app.get("/jobs")
|
||||
async def jobs(request: Request) -> dict[str, Any]:
|
||||
await require_token(request, runtime, scope=SCOPE)
|
||||
return await scheduler_of().snapshot()
|
||||
|
||||
@app.post("/jobs/{name}/run", status_code=status.HTTP_202_ACCEPTED)
|
||||
async def run_job(name: str, request: Request) -> dict[str, Any]:
|
||||
await require_token(request, runtime, scope=SCOPE)
|
||||
scheduler = scheduler_of()
|
||||
job = scheduler.job(name)
|
||||
if job is None:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, f"no job {name!r}")
|
||||
return {"job": await scheduler.trigger(job, await body_of(request))}
|
||||
|
||||
@app.delete("/jobs/queue/{job_id}")
|
||||
async def cancel_job(job_id: int, request: Request) -> dict[str, Any]:
|
||||
await require_token(request, runtime, scope=SCOPE)
|
||||
if not await scheduler_of().cancel(job_id):
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, f"no queued job {job_id}")
|
||||
return {"cancelled": job_id}
|
||||
|
||||
@app.post(
|
||||
"/conversations/{public_id}/schedule", status_code=status.HTTP_201_CREATED
|
||||
)
|
||||
async def post_schedule(public_id: str, request: Request) -> dict[str, Any]:
|
||||
await require_token(request, runtime, scope=SCOPE)
|
||||
conv = await conv_of(public_id)
|
||||
data = await body_of(request)
|
||||
try:
|
||||
job_id, when = await conversations.schedule(
|
||||
conv, text_of(data, "at"), text_of(data, "text")
|
||||
)
|
||||
except (RuntimeError, ValueError) as exc:
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, str(exc)) from exc
|
||||
return {"job": job_id, "execute_at": _iso(when)}
|
||||
|
||||
@app.get("/usage")
|
||||
async def usage(request: Request) -> dict[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user