Skip to content

shreds: flag lagging publishers on the shred publishers page - #666

Open
SinaVafadar wants to merge 4 commits into
mainfrom
sv/publisher-lagging-status
Open

shreds: flag lagging publishers on the shred publishers page#666
SinaVafadar wants to merge 4 commits into
mainfrom
sv/publisher-lagging-status

Conversation

@SinaVafadar

Copy link
Copy Markdown
Contributor

Summary

  • Adds a Lagging column to the Shred Publishers page (/dz/shreds/publishers) that flags validators reported as not Healthy in dzf_data.lagged_validators.
  • The lagging status text (the non-Healthy value from the table) is shown in the cell and on hover, and the column is sortable.
  • Wires up the dzf_data ClickHouse database (config default, CLICKHOUSE_DZF_DATA_DB env override, and API plumbing) so the handler can read the table.

Details

FetchPublisherCheckData now joins publishers against dzf_data.lagged_validators by validator_vote_public_key, selecting rows where status != 'Healthy'. Matching publishers are annotated with lagging and lagging_status. The lookup is non-fatal — if the table is unavailable the page still renders without lagging annotations. Because the logic lives in FetchPublisherCheckData, the background page cache picks up the new fields automatically.

Testing Verification

  • Existing PublisherCheck handler tests pass; the lagged-validators lookup degrades gracefully when the table is absent in the test DB (logged warning, publishers returned unannotated).

Pulls validators reported as not Healthy from dzf_data.lagged_validators
and annotates matching shred publishers with a new Lagging column. Adds
dzf_data database plumbing (config, env var, API wiring) and a non-fatal
lookup in FetchPublisherCheckData so the page still renders if the table
is unavailable.
@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown

🔗 Preview: https://pr-666.data.malbeclabs.com

@ben-dz ben-dz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lagging column ships with an internal contradiction and no verification of its success path. The backend flags any status != 'Healthy' (and the sort uses that boolean), but the icon is red only for the exact string "Action Needed" — a value that appears nowhere in the backend and isn't documented anywhere — so any other non-Healthy status sorts as lagging while displaying a green check. The test harness never sets DZFDataDB, so fetchLaggedValidators always errors in tests and every existing test exercises only the warn-and-degrade branch; the read-only prod ClickHouse user has no grant on dzf_data.lagged_validators, so the deployed API user's grant should be confirmed before merge or the column ships permanently green. Also worth addressing: the query assumes the externally-written table holds only current state (no recency bound or dedup), and lagging_status is never actually shown in the UI despite the PR description saying it appears in the cell and on hover.

</td>
<td className="px-4 py-3 text-center">
<StatusIcon
ok={pub.lagging_status !== "Action Needed"}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This predicate disagrees with the backend and the sort. The backend sets lagging=true for any status != 'Healthy' (publisher_check.go:386) and the sort comparator uses that boolean (line 417), but the icon is red only for the exact string "Action Needed" — a value that appears nowhere in the backend or the repo, from a table whose status vocabulary is undocumented. Any other non-Healthy value (or a casing change by the external writer) yields a row that sorts as lagging while showing a green check; rows with status='' are also flagged lagging with a green icon, and an undefined lagging_status during deploy skew renders green too. Use one predicate: ok={!pub.lagging} (also handles undefined), or filter the SQL to status = 'Action Needed' so the flag, sort, and icon agree.

// fetchLaggedValidators returns a map of validator vote pubkey to its lagging
// status for every validator currently reported as not Healthy in
// dzf_data.lagged_validators.
func (a *API) fetchLaggedValidators(ctx context.Context) (map[string]string, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The success path of this function is never verified anywhere. The test harness (api/testing/api.go) never sets DZFDataDB, so in every existing test this builds FROM ` `.lagged_validators with an empty identifier and always errors — the tests cited in the PR only exercise the warn-and-degrade branch. Fix: set DZFDataDB in the harness constructors (e.g. to the per-test dbName), seed a lagged_validators fixture following the createPublisherShredStatsTable pattern with a Healthy row, a non-Healthy row matched to a fixture vote pubkey, and an unmatched pubkey, and assert lagging/lagging_status on the response — this also pins the status-string contract. Separately, the read-only prod ClickHouse user has no SELECT grant on dzf_data.lagged_validators (verified), so please confirm the deployed API user's grant before merge; if it's missing, the column ships permanently green with only a server-side warn every 30s.

query := fmt.Sprintf(`
SELECT validator_vote_public_key, status
FROM `+"`%s`"+`.lagged_validators
WHERE status != 'Healthy' AND validator_vote_public_key != ''`, a.DZFDataDB)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes the table holds only current state: no recency bound, no FINAL/argMax dedup, and arbitrary last-write-wins in the map when a pubkey has multiple rows. The table is written by an external process and its schema/engine exists nowhere in this repo. If it's append-mode (or a pre-merge ReplacingMergeTree), a recovered validator stays flagged; if the writer stops, flags freeze silently. Confirm the write contract (full replace per cycle?) and document it here, or dedup to latest state per pubkey with a recency bound.

<StatusIcon ok={!pub.publishing_retransmitted} />
</td>
<td className="px-4 py-3 text-center">
<StatusIcon

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lagging_status is never shown: the PR description says the status text appears in the cell and on hover, but StatusIcon accepts only ok and the cell has no title, so the field is shipped to the client and only feeds the string comparison. The legend box above the table also explains the other two icon columns but not "Fast Shreds". Add title={pub.lagging_status || undefined} to the cell and a legend entry (and update the PR description) — or drop the field if it has no UI consumer after unifying the predicate.

// in dzf_data.lagged_validators. Non-fatal: if the lookup fails we still
// return publisher data without lagging annotations.
if lagging, err := a.fetchLaggedValidators(ctx); err != nil {
slog.Warn("publisher check: lagged validators query failed", "error", err)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The page-cache worker refreshes publisher_check every 30s, so any environment where the table is absent (local dev without remote tables) or the grant is missing logs this warning every 30s indefinitely. Consider skipping the lookup when !isMainnet(ctx) and/or probing table availability once at startup.

Comment thread api/config/config.go
}

// SetDZFDataDB sets the dzf_data database name.
func SetDZFDataDB(db string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetDZFDataDB has no callers — the env-var override in Load() is the only write path. Drop the setter.

@ben-dz ben-dz removed the preview label Jul 28, 2026
@ben-dz

ben-dz commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Removing the Preview label. noticed while debugging something else:

lake-pr-666 has been emitting ~1M log lines per 5 minutes (~3.5k/sec) for at least 4 hours — a hot dzingest: workflow interrupted, reattaching loop on dz_env=testnet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants