A subgraph's health reports the store's cursor, not this process's

Status() counts what the running indexer has ingested since it started. On a
chain already at its head a restart ingests nothing, so /v1/graph/{slug}/{sub}/
health answered {"block":0,"indexed":0} with every event still in the store —
measured on cchain, which reported block 19 before a restart and block 0 after,
while the same subgraph's GraphQL kept answering with its token.

That is the one reply a reader checks this endpoint to avoid. Read `block` from
store.GetLastBlock(), which is the cursor that persists, and keep the process
count where it is higher — a fresh store mid-first-pass has moved further than
it has committed. `indexed` stays the process count: nothing persists an event
total, and a second number meaning something else under the same name is how
this went wrong once.

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
2026-09-08 19:55:00 -07:00
co-authored by Hanzo Dev
parent e44378c65e
commit 2d8e8c756e
+12 -1
View File
@@ -466,10 +466,21 @@ func (s *ChainSupervisor) runSubgraph(ctx context.Context, cfg ChainConfig, sg S
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
}
// `block` is the cursor the STORE holds, not the one this process has moved.
// Status() counts what the running indexer has ingested since it started, so
// a restart on a chain already at its head reports `block:0, indexed:0` while
// the store holds every event — which reads as an empty index and is the
// reply a reader checks this endpoint to avoid. `indexed` stays the process
// count: nothing persists an event total, and a second number that means
// something else under the same name is how this went wrong once.
statusHandler := func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
st := idx.Status()
fmt.Fprintf(w, `{"status":"ok","block":%d,"indexed":%d}`, st.LatestBlock, st.IndexedEvents)
block := store.GetLastBlock()
if st.LatestBlock > block {
block = st.LatestBlock
}
fmt.Fprintf(w, `{"status":"ok","block":%d,"indexed":%d}`, block, st.IndexedEvents)
}
mux.HandleFunc("POST "+prefix+"/graphql", gqlHandler)
mux.HandleFunc("GET "+prefix+"/graphql", eng.HandleGraphiQL)