feat(jobs): useJobsRealtime fetch-on-unknown met dedup-Set
Wanneer een SSE-event een onbekend job_id bevat, haalt de hook de volledige job op via GET /api/jobs/[id] en upsert die in de store. Een inFlight-Set voorkomt gelijktijdige dubbele fetches voor hetzelfde job_id. Bekende jobs blijven de bestaande partial-upsert gebruiken. Zelfde logica in jobs_initial. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c70ec17b79
commit
b76ae290e3
2 changed files with 183 additions and 9 deletions
|
|
@ -24,6 +24,22 @@ export default function useJobsRealtime() {
|
|||
let es: EventSource | null = null
|
||||
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
|
||||
let active = true
|
||||
const inFlight = new Set<string>()
|
||||
|
||||
async function fetchAndUpsert(jobId: string) {
|
||||
if (inFlight.has(jobId)) return
|
||||
inFlight.add(jobId)
|
||||
try {
|
||||
const res = await fetch(`/api/jobs/${jobId}`)
|
||||
if (!res.ok) return
|
||||
const job = await res.json()
|
||||
if (active) upsertJob(job)
|
||||
} catch {
|
||||
// netwerk-/parse-fout: stil
|
||||
} finally {
|
||||
inFlight.delete(jobId)
|
||||
}
|
||||
}
|
||||
|
||||
function connect() {
|
||||
if (!active) return
|
||||
|
|
@ -34,20 +50,25 @@ export default function useJobsRealtime() {
|
|||
// De server stuurt JobPayload[] (met `job_id`), niet JobWithRelations[].
|
||||
// Daarom geen initJobs-overwrite — de SSR-fetch heeft de volledige
|
||||
// shape al in de store geplaatst. We reconcileren alleen status/branch
|
||||
// van bekende jobs en pushen onbekende jobs (nieuw aangemaakt tussen
|
||||
// SSR en SSE-connect) als partials.
|
||||
// van bekende jobs en fetchen onbekende jobs volledig via REST.
|
||||
try {
|
||||
const payload = JSON.parse(event.data)
|
||||
if (!Array.isArray(payload)) return
|
||||
const { activeJobs, doneJobs } = useJobsStore.getState()
|
||||
for (const p of payload as JobStatusPayload[]) {
|
||||
if (!p.job_id) continue
|
||||
upsertJob({
|
||||
id: p.job_id,
|
||||
status: p.status as ClaudeJobStatus,
|
||||
branch: p.branch ?? null,
|
||||
error: p.error ?? null,
|
||||
summary: p.summary ?? null,
|
||||
})
|
||||
const known = activeJobs.some(j => j.id === p.job_id) || doneJobs.some(j => j.id === p.job_id)
|
||||
if (!known) {
|
||||
void fetchAndUpsert(p.job_id)
|
||||
} else {
|
||||
upsertJob({
|
||||
id: p.job_id,
|
||||
status: p.status as ClaudeJobStatus,
|
||||
branch: p.branch ?? null,
|
||||
error: p.error ?? null,
|
||||
summary: p.summary ?? null,
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// malformed JSON
|
||||
|
|
@ -58,6 +79,12 @@ export default function useJobsRealtime() {
|
|||
try {
|
||||
const payload = JSON.parse(event.data) as JobStatusPayload
|
||||
if (!payload.job_id) return
|
||||
const { activeJobs, doneJobs } = useJobsStore.getState()
|
||||
const known = activeJobs.some(j => j.id === payload.job_id) || doneJobs.some(j => j.id === payload.job_id)
|
||||
if (!known) {
|
||||
void fetchAndUpsert(payload.job_id)
|
||||
return
|
||||
}
|
||||
upsertJob({
|
||||
id: payload.job_id,
|
||||
status: payload.status as ClaudeJobStatus,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue