T-HUB/apps/api/migrations/042_probe_jobs_claimable.sql
glass beadian 1429e4e9af feat: video direct-to-R2 ingest — browser seals, worker probes off R2
POST /video/direct/init|complete: the browser seals (SPENC2) and PUTs
straight to object storage; the api HEAD-checks, registers the unprobed
asset and queues a probe job — video bytes never cross the api box.

Worker side: produce_job_claim widened to probe jobs (042), the runner
gains a probe lane (sealed fetch → SPENC1/SPENC2 open by magic → scratch →
ffprobe → metadata write-back → complete 100), worker storage reads SPENC2
frames via DIRECT_EC_PRIVATE_KEY (inherited through compose appenv), and a
ported ffprobe util. Probe rows carrying input_json fail instead of
stranding; the claim guard no longer strands probe rows as invalid.
2026-10-16 10:52:47 +00:00

48 lines
1.8 KiB
PL/PgSQL

-- 042: the produce worker claims PROBE jobs too.
--
-- Direct-to-R2 video uploads register an unprobed asset plus a queued probe
-- job and return immediately — the api never touches the bytes, so it cannot
-- probe inline the way 009's ingest path does. The worker (which can decrypt
-- SPENC2 frames via DIRECT_EC_PRIVATE_KEY) owns the probe from here on.
--
-- Same body as 040 with the kind filter widened; 'transcoding' remains the
-- lease state (the UI's in-flight set already covers queued/probing/transcoding).
CREATE OR REPLACE FUNCTION produce_job_claim(p_lane text, p_stale_after interval)
RETURNS TABLE (
id uuid,
workspace_id uuid,
kind text,
input_json jsonb,
video_asset_id uuid
)
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$
BEGIN
UPDATE video_processing_jobs stale
SET state = 'queued', progress_percent = 0, error = NULL, updated_at = now()
WHERE stale.state = 'transcoding'
AND stale.updated_at < now() - p_stale_after;
RETURN QUERY
UPDATE video_processing_jobs j
SET state = 'transcoding', progress_percent = 5, error = NULL, updated_at = now()
WHERE j.id IN (
SELECT c.id
FROM video_processing_jobs c
WHERE c.kind IN ('probe', 'compose', 'mix')
AND c.state = 'queued'
AND (
(p_lane = 'remote' AND c.input_json->>'lane' = 'remote')
OR (p_lane <> 'remote' AND c.input_json->>'lane' IS DISTINCT FROM 'remote')
)
ORDER BY c.created_at, c.id
FOR UPDATE SKIP LOCKED
LIMIT 1
)
RETURNING j.id, j.workspace_id, j.kind, j.input_json, j.video_asset_id;
END
$$;
-- Ownership unchanged from 040.
REVOKE ALL ON FUNCTION produce_job_claim(text, interval) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION produce_job_claim(text, interval) TO sp_app;