Skip to content

Flaky gate: TestEdgeRollupBacklog fails when a minute ticks between its two setup inserts #189

Description

@vishr

TestEdgeRollupBacklog fails intermittently on the bucket-count assertion:

edge_backlog_test.go:130: edge_rollup has 180 distinct buckets, spans have 181
  distinct minute buckets — sub-windowing dropped or duplicated buckets

Seen on CI in
run 32686288421.
It passes locally, including -count=8 in a row, which is consistent with the
cause below rather than with a real sub-windowing bug.

Cause

The test builds its dataset with two separate statements — parents at
edge_backlog_test.go:42, children at :71 — and both place rows relative to
their own now():

now() - ((i % 180) * INTERVAL '1' MINUTE)

Each statement therefore covers 180 whole-minute buckets measured from whenever
it ran. The assertion at :125 counts distinct minutes across all spans:

SELECT count(DISTINCT date_trunc('minute', start_time)) FROM lake.spans

If the wall clock crosses a minute boundary between the two inserts — each
writes 400,000 rows, so the gap is seconds — the two windows are offset by one
minute and their union is 181 distinct buckets. edge_rollup is built from
the joined edges and aligns to one window, giving 180, and the assertion fails.

So the failure means "a minute ticked mid-setup", not "sub-windowing dropped a
bucket". The probability is roughly the gap between the two inserts divided by
60 seconds, which is why it is rarer locally than on a loaded runner.

The assertion is worth keeping

It is a good check — it is what proves sub-windowing neither drops nor
duplicates a bucket, which is the regression the test exists for. The fix is to
make the dataset deterministic rather than to weaken it. Options, roughly in
order of preference:

  1. Pin one base timestamp in Go and pass it to both statements, so every row
    is placed relative to the same instant. Removes the race entirely and makes
    the expected bucket count exactly 180, which is a stronger assertion than
    "the two counts agree".
  2. Compute the base once in SQL and reuse it, e.g. a CTE or a temp value both
    inserts read.
  3. Insert parents and children in a single statement.

Not caused by

internal/query and internal/lake are untouched by the branch this surfaced
on (#187), which changes documentation, cmd/fanout-docgen, and an additive
read-only accessor in internal/api.

Related in spirit to labstack/onebox#112 — a gate failing on a timing
assumption rather than on the behaviour under test.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions