Skip to content

Fixes #33133: optimize java-playwright-nightly - #33134

Draft
mohityadav766 wants to merge 8 commits into
mainfrom
optimize/java-playwright-nightly
Draft

Fixes #33133: optimize java-playwright-nightly #33134
mohityadav766 wants to merge 8 commits into
mainfrom
optimize/java-playwright-nightly

Conversation

@mohityadav766

@mohityadav766 mohityadav766 commented Sep 10, 2026

Copy link
Copy Markdown
Member

Describe your changes:

Fixes #33133

java-playwright-nightly.yml (the required java-ui-it check) ran ~84 min on every search-indexing PR. I profiled run 34447075164 — failsafe reports, job step timings and the recorded Playwright videos — and found three separate causes, only one of which was "the tests are slow". Full evidence in the issue.

1. A 15-minute no-op in two tests (30 of the 59 minutes). In the videos, all four pages open within 21s and the UI work finishes by ~80s; the page then sits idle for ~900s. TestNamespaceExtension.afterEach runs before the browser context closes, and NamespaceCleanup.CASCADE_TIMEOUT was 15 min. This turned out to be a production bug: a cascade hard-delete of any service with an ingestion pipeline underneath it aborts outright when Airflow is unreachable, because AirflowRESTClient throws the generic PipelineServiceClientException where deleteDeployedPipeline only tolerates the typed IngestionRunnerUnavailableException subclass.

2. Every PR ran the full nightly stress cohort. github.event.inputs.* is empty on pull_request, so || '5000' always won — 10,000 entities ingested where the in-test defaults are 200/100/100/100.

Type of change:

  • Bug fix
  • Improvement

High-level design:

Test dedup (−3,640 lines). Deleted 23 UIITs whose scenario is already asserted in the UI suite, plus the 8 page objects left with no referrer. Audited class-by-class against the specs rather than by name:

Java UIIT Covering UI spec
DataQuality{Table,Column}TestCaseCrudReindexUIIT DataQuality.spec.ts → "Table/Column test case" Create/Edit/Delete
DataQuality{ArrayParams,Filters,Pagination}ReindexUIIT DataQuality.spec.ts
DataQualityDashboardDimensionAndPieReindexUIIT DataQualityDashboard.spec.ts
StandaloneDQDashboardFiltersReindexUIIT, {Tag,GlossaryTerm,Domain}DataObservability* (5) DataObservabilityGovernanceTab.spec.ts
IncidentManager{Acknowledge,AssignResolve,Resolve,Filters}ReindexUIIT, IncidentTabOnEntityPage* (5) IncidentManager.spec.ts
IncidentManagerPaginationReindexUIIT IncidentManagerPagination.spec.ts
ProfilerSettingsModalReindexUIIT, TableProfilerColumnGraphsReindexUIIT Profiler.spec.ts
TestSuiteCrudReindexUIIT (already @Disabled), TestSuiteDetailsPageReindexUIIT TestSuite.spec.ts, TestSuiteDetailsPage.spec.ts
TopicUIIT, TableDetailsSmokeUIIT Topic.spec.ts, Entity.spec.ts

Kept: the 8 search-indexing UIITs with no UI equivalent (SearchAvailable*, SimpleReindexTrigger, DistributedAutoTune, SelectiveFieldReindex, LongCompoundNameSearch, PipelineOwnerIndex, EntityLoaderSmoke) and all 29 search-it classes. Also kept GoogleSsoSignInUIIT — it's skipped unless jpw.auth=sso-google-confidential, so it costs 0s and shares the mock-IdP harness with the two backend SSO tests; deleting it is churn with no speed gain.

Delete fix. AirflowRESTClient now throws IngestionRunnerUnavailableException for a failed API detection — it's a subclass, so every existing catch of the parent still works. EntityRepository tracks whether the thread is inside a hard-delete cascade (same ThreadLocal pattern DomainRepository already uses) and IngestionPipelineRepository tolerates an unreachable runner when it is. Deleting the DAG is best-effort cleanup of an external system; a direct delete of the pipeline still surfaces the failure, which is the behaviour worth keeping.

CI restructure. Dropped the build-image job — it serialised ~17 min in front of every leg to hand over a 461 MB artifact each leg then loaded alone. Each leg now builds its own image, overlapping that with its own setup; the shared GHA layer scope keeps it warm and only one leg writes so concurrent legs don't duplicate blobs. Trimmed Free Disk Space to android (the only target worth its runtime) and dropped the Python-ingestion apt-get list from these Java-only jobs.

Both suites are serial within a runner because they mutate cluster-global search state, so a shard matrix is the only parallelism available: ui-it ×2, search-it ×3. ShardFilter is a ServiceLoader PostDiscoveryFilter assigning by hash(className) % total.

Alternatives rejected: a checked-in class list per shard (needs manual rebalancing and silently drops any test nobody adds); enabling class-level parallelism in the pom (these tests mutate cluster-global state, so @ResourceLock would serialise them anyway); moving the remaining UIITs to the embedded bootstrap (UiTestServer supports only External/Containerized — no embedded path, which is exactly why ui-it needs the image and search-it doesn't).

Rollout: no schema, migration or API-contract change. The delete fix is behaviour-affecting in one direction only — cascades that previously failed now succeed, logging a warning about the orphaned DAG.

Tests:

Use cases covered

  • Hard-deleting a database service that owns a table with test cases succeeds while Airflow is unreachable (previously aborted and rolled back the whole subtree)
  • Directly deleting an ingestion pipeline while Airflow is unreachable still fails loudly
  • Column profile charts still render after a recreate reindex of the table
  • A sharded run executes each test class on exactly one shard

Unit tests

  • Added ShardFilterTest — 4 tests pinning the partition invariants: every class claimed by exactly one shard across 2–8 shards, stable assignment, total=1 keeps everything, no degenerate partition.
  • NamespaceCleanupTest still pins the non-fixed poll interval.

Backend integration tests

Not applicable — no new API endpoints. The delete fix is exercised by the existing UIIT cleanup path, which is what surfaced it: the two runs that hit it logged Cleanup cascade for databaseService … still running after PT15M / deleted 0/1.

Ingestion integration tests

Not applicable — no ingestion changes.

Playwright (UI) tests

  • Added playwright/e2e/Features/DataQuality/ColumnProfileGraphsAfterReindex.spec.ts, the one assertion from the deleted Java suite with no UI equivalent. Profiler.spec.ts already asserts the four graphs (#count_graph, #proportion_graph, #math_graph, #sum_graph) inside validateProfilerAccessForRole, but not post-reindex. Modelled on the existing TestCaseStatusAfterReindex.spec.ts.

Manual testing performed

  1. mvn compile -pl :openmetadata-service → BUILD SUCCESS
  2. mvn test-compile -pl :openmetadata-integration-tests → BUILD SUCCESS (confirms no dangling refs to the deleted classes)
  3. mvn spotless:apply on both modules → clean
  4. Verified the shard filter empirically rather than assuming ServiceLoader registration engages:
    • -Djpw.shard.total=2 -Djpw.shard.index=0Tests run: 4 (ShardFilterTest)
    • -Djpw.shard.total=2 -Djpw.shard.index=1Tests run: 0
    • unsharded → Tests run: 4
  5. Workflow YAML parses; UI_IT_SHARDS/SEARCH_IT_SHARDS verified equal to their matrix list lengths
  6. Prettier 2.8.8 (repo-pinned) applied to the new spec

UI screen recording / screenshots:

Not applicable — no product UI changes; the only UI-tree file is a new Playwright spec.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR is linked to a GitHub issue via Fixes #33133 above.
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: not applicable.
  • For UI changes: not applicable (no product UI change).
  • I have added tests (unit / Playwright) and listed them above.
  • I have added a test that covers the exact scenario we are fixing.

Note for reviewers

Two things I could not verify locally:

  • The ~18-19 min projection is a projection. The deletion (−38.8 min of test time) and the cohort fix are measured, but the setup-time estimates behind the restructure come from the old run's step timings. The first CI run on this PR is the real check. UI_IT_SHARDS / SEARCH_IT_SHARDS in env: are the dial.
  • Runner cost goes up. Four ui-it legs each build the dist tarball and image instead of one shared job — that's the trade that buys the wall clock. If cost matters more than the last few minutes, running only OpenSearch on PRs and both engines on dispatch halves it. I left both on because changes already gates this to search-indexing PRs, which is exactly where engine differences bite.

🤖 Generated with Claude Code

mohityadav766 and others added 3 commits September 10, 2026 16:27
Twenty-three of the 34 *UIIT.java classes document themselves as "Java port of
<spec>.ts", and every spec they name exists in the UI suite. They asserted the
same UI behaviour a second time, in a slower harness, and cost 38.8 of the 58.4
minutes the ui-it matrix spent running tests.

The one thing the ports added was a reindexEntities call between UI mutations.
That is already an established pattern in the UI suite -- TestCaseStatusAfterReindex,
TestSuiteListAfterReindex and TestSuiteSummaryAfterReindex each inject one against
a real regression -- so it is not a reason to keep a parallel Java copy of the
whole DataQuality/IncidentManager/Profiler surface.

Kept: the eight search-indexing UIITs with no UI equivalent, and GoogleSsoSignInUIIT
(skipped unless jpw.auth=sso-google-confidential, so it costs nothing and shares the
mock-IdP harness with the two backend SSO tests).

The only assertion with no home in the UI suite was "column profile charts still
render after a reindex" -- Profiler.spec.ts already asserts the four graphs, but not
post-reindex. Ported to ColumnProfileGraphsAfterReindex.spec.ts.

Also deletes the eight page objects left with no referrer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…able

A recursive hard delete of any service with an ingestion pipeline underneath it
aborted outright whenever the pipeline service client could not reach Airflow:

  IngestionPipelineRepository.postDelete -> deleteDeployedPipeline
    -> AirflowRESTClient.deletePipeline
    -> PipelineServiceClientException: Unable to connect to Airflow APIs

The exception propagated out of the cascade and rolled the subtree back, so the
service survived. The async endpoint had already answered 202, which left the
failure visible only in a server-side ERROR line -- callers just saw the entity
never disappear.

deleteDeployedPipeline already had a tolerance path, but it catches
IngestionRunnerUnavailableException and the connectivity failure threw the generic
parent, so the typed handler never fired. Two changes:

- AirflowRESTClient throws IngestionRunnerUnavailableException for a failed API
  detection. It is a subclass, so every existing catch of the parent still works.
- EntityRepository tracks whether the current thread is inside a hard-delete
  cascade (same ThreadLocal pattern DomainRepository already uses), and
  IngestionPipelineRepository tolerates an unreachable runner when it is. Deleting
  the DAG is best-effort cleanup of an external system; a direct delete of the
  pipeline itself still surfaces the failure.

On the test side this was billing 15 idle minutes per occurrence: NamespaceCleanup
polls for a 404 that a failed cascade never produces. Default cap drops 15 -> 2 min;
scale-it and seed-it pin 15 explicitly because they really do delete a 100k-table
service.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ge job

Critical path was build-image (17m) -> ui-it-nightly (64m) = ~84m. Three structural
costs, none of them test logic:

- build-image serialised ~17 min in front of every test job to hand over a 461 MB
  image artifact each leg then loaded alone. Each leg now builds its own image,
  overlapping that work with its own setup and dropping the artifact round-trip.
  The shared GHA layer scope keeps it from being a cold build; only one leg writes,
  so concurrent legs do not duplicate blobs.
- Free Disk Space ran every target (308s in build-image, 72-99s per test job) for
  space these jobs never needed. android alone reclaims ~9 GB in seconds.
- The apt-get list (unixodbc, librdkafka, sasl, ffi...) exists for the Python
  ingestion build; nothing in these Java-only jobs links against it. ANTLR stays.

Both suites are serial *within* a runner because they mutate cluster-global search
state, so the shard matrix is the only parallelism available: ui-it x2, search-it x3.
ShardFilter is a ServiceLoader PostDiscoveryFilter keyed on jpw.shard.total/index,
assigning by hash(className) % total rather than a checked-in class list -- a list
needs manual rebalancing and silently drops any test nobody remembered to add.

Also fixes cohort sizing: github.event.inputs.* is empty on pull_request, so the
unconditional `|| '5000'` fallback meant every PR ingested the full nightly stress
cohort (10k entities) instead of the 200/100/100/100 baked into each test. Those
props are now set only on workflow_dispatch, which is what the comment above them
always claimed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions github-actions Bot added backend safe to test Add this label to run secure Github workflows on PRs labels Sep 10, 2026
@mohityadav766 mohityadav766 changed the title Fixes #33133: get java-playwright-nightly under 20 minutes Fixes #33133: optimize java-playwright-nightly Sep 10, 2026
mohityadav766 and others added 2 commits September 10, 2026 16:50
The deleted UIITs each injected a reindex mid-flow and re-asserted. Deleting them kept
the product behaviour covered (DataQuality/IncidentManager/Profiler/DataObservability
specs already assert it) but dropped the post-reindex dimension for ~20 surfaces, leaving
only the three existing *AfterReindex specs. That dimension is the one worth keeping:
reindex rebuilds a doc from the fields each index declares in getRequiredReindexFields(),
so a field the UI reads through search but nobody declared disappears on rebuild while the
live-write path keeps working — exactly the shape of the 1.12.7 and PR-27723 regressions.

Adds utils/reindex.ts (trigger + wait for the doc to come back; no ?recreate=true, since
SearchResource.reindexEntities declares no such param and always ignored it) and specs for:

- TestCaseCrudAfterReindex: row still listed, UI-edited parameterValues and array params
  survive. Was DataQuality{Table,Column}TestCaseCrud + ArrayParams.
- IncidentManagerAfterReindex: acknowledged status survives, entity-page Incidents tab rows
  survive, list still paginates. Was IncidentManager{Acknowledge,Resolve} + IncidentTab.
- DataObservabilityTabsAfterReindex: tag / glossary term / domain tabs still load their
  widgets after that governance entity is rebuilt. Was the four DataObservability UIITs.
- DataQualityListAfterReindex: /data-quality list still paginates and name-searches.
  Was DataQualityPagination + DataQualityFilters.
- DataQualityDashboardAfterReindex: widgets still have data and the filter bar renders.
  Was DataQualityDashboardDimensionAndPie + StandaloneDQDashboardFilters.
- ProfilerSettingsAfterReindex: tableProfilerConfig survives a table rebuild.

Not ported: TestSuiteCrudReindexUIIT (was @disabled) and TestSuiteDetailsPageReindexUIIT,
whose post-reindex assertion is that a modal's filter dropdowns render — a routing concern
the rebuild does not touch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
First CI run on the restructure measured what the projections could not:

- Free Disk Space 308s -> 24s and the docker build 213s -> 41s (shared GHA layer scope).
  Folding build-image into the legs worked; the 17-min serial block is gone.
- A shard holding one 1-second test still took 13.2m, so fixed cost, not test time, is now
  what sets the floor. Of that, 467s is Maven (146s integration-tests + 321s dist) and
  ~170s is the OM stack starting per shard.

So: one reactor pass for integration-tests + dist instead of two (as separate invocations
Maven walked spec/common/sdk/service twice), with -T 1C across the runner's cores.

Replaces ShardFilter with `find | sort | awk 'NR % t == i'`. The hash filter partitioned
fine over 500 synthetic names and uselessly over the real ones — 8 of 9 classes landed on
one shard, which is no speedup at all, and its balance test never exercised a suite that
small. Its own unit test therefore passed on a property the real input does not have.
Deleting it is also a smaller diff than keeping it: no Java, no ServiceLoader registration.

File order is not a balance guarantee either (N=3 was worse than N=2 — the slow Search*
classes sort adjacent), which is why the comment says to cut fixed cost before adding
shards rather than reaching for a hand-maintained duration table.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment on lines +72 to +86
/** Polls the entity's alias until its id matches exactly one doc. */
const waitForIndexed = async (
apiContext: APIRequestContext,
target: ReindexTarget
): Promise<void> => {
const index = SEARCH_INDEX_BY_TYPE[target.type];

if (!index) {
throw new Error(
`No search index mapped for entity type '${target.type}' — add it to SEARCH_INDEX_BY_TYPE`
);
}

await expect
.poll(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Edge Case: waitForIndexed may pass on the stale pre-reindex doc

reindexEntities triggers the rebuild and then waitForIndexed polls the search alias until it sees exactly one hit for the id. The backend reindex deletes the doc and re-creates it, but if the endpoint returns before the async delete has run (the file's own comment states it is async — 'answers 202 and runs on the executor'), the first poll observes the still-present old document, returns 1, and resolves immediately — so the subsequent assertions can race the rebuild the specs exist to validate, giving false-green or flaky results. If the endpoint instead blocks until completion (it calls future.get(...)), the wait is simply redundant. Consider gating on a value the rebuild changes (e.g. poll a field/version that reindex updates, or delete-then-wait-for-reappear) rather than mere presence of any doc for the id.

Was this helpful? React with 👍 / 👎

mohityadav766 and others added 3 commits September 10, 2026 17:15
Measured on run 34470830757: the four ui-it legs build an identical image, and three of
them finished that step in ~41s against 272s for the fourth. The odd one out was the
designated cache writer — mode=max exports every layer — and that +231s is the entire
reason the slowest job came in at 20.1m while its same-shard twin took 16.7m.

A PR run cannot benefit from its own write anyway: all four legs start together, so the
export only ever helps a later run. Writing solely on workflow_dispatch takes it off the
critical path without adding a job.

That is safe rather than lucky because the layer worth caching does not change per PR.
The Dockerfile is 3-stage and the expensive stage is jre-builder (jlink over the JDK base
image); only the cheap `dist` untar layer moves with the tarball, which is why read-only
legs still got 41s. mode=min was the other candidate and is wrong here — it skips
intermediate stages, so every leg would rebuild the JRE.

Cold-build fallback if the builder stage or its base image changes: ~230s per leg until
someone dispatches once to repopulate. Degraded, not broken.

Expected worst leg ~16.7m.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every scheduled main run of the nightly k8s Java IT fails in search-it, always the same
four tests, each dying in under 0.2s:

  java.net.ConnectException
    at HighlightFieldSaveValidationIT.currentSettingsJson(...:240)

SdkClients.BASE_URL initialises from IT_BASE_URL and otherwise localhost:8585. The CI login
script exports OM_URL / OM_ADMIN_TOKEN, which UiTestServer reads — so a test that goes
through a harness gets pointed at the ephemeral cluster, and a test that talks to the server
directly (HttpClient + getServerUrl()) does not. HighlightFieldSaveValidationIT has no
@BeforeAll and no extension, so it only worked when some other class happened to boot the
harness first and call overrideBaseUrl. Whether the suite passed came down to test order,
which is why it fails on main but not on the 1.13/2.0 dispatch runs.

Reading OM_URL at BASE_URL init makes external mode correct from static init for every
entry point, harness or not.

Costs the nightly ~7.7h per failed run today: scale-it gates only on deploy, so search-it
failing does not stop the 460m scale job that follows it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…Loader

This test was 125.1m of the nightly k8s Java IT's 300m — 42% of the whole workflow — and
its own log says where it went:

  Seeded 100000 tables (5 columns each) in 6411160 ms          <- 106.9m
  Recursive async hard delete ... cleared search in 1089795 ms <- 18.2m

Seeding was 85% of it, done by a local fixed-thread executor issuing one
SdkClients.adminClient().tables().create(...) per table. EntityLoader does the identical
work — same 100k tables, same 5 columns — and on the same run, same cluster, same
parallelWorkers=8, logged:

  EntityLoader done: created=100000 columns=500000 duration=PT29M14.478571946S

57.0 tables/s against this executor's 15.6/s, a 3.65x gap for the same work at the same
concurrency. EntityLoader's rate also held flat as the cluster filled (59.9 -> 55.9 -> 57.0
tables/s across the 10k, 50k and 100k cohorts that ran before it), so dataset growth does not
account for the difference.

Both seeders' concurrency now comes from one property. The executor read jpw.scale.workers
while EntityLoader reads jpw.loader.maxWorkers, and the nightly only ever set the latter —
so the workflow input documented as "the cap on create concurrency" was never reaching the
most expensive seeder in the suite. Requesting 32 and letting maxWorkers cap it matches what
Scale100kEntitiesIT already does.

The service is now read back off the namespace rather than created up front: EntityLoader
builds its own service+schema in ensureTablesSchema, and creating one here first would leave
the seeded tables under a different service than the one deleted — the scoped doc counts
would then pass against an empty service, which is the one way this test can go green while
testing nothing.

Assertions are unchanged: 100k table docs and 500k column docs scoped by service.id before
the delete, zero of each after.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gitar-bot

gitar-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown
Code Review 👍 Approved with suggestions 1 resolved / 2 findings

Comprehensive optimization of the java-playwright-nightly CI pipeline that eliminates 30 minutes of test idle time, deduplicates 23 UIITs already covered by the Playwright suite, and restructures CI to parallelize image builds across shards. Fixes a production bug where cascade hard-deletes of services with ingestion pipelines fail when Airflow is unreachable by having AirflowRESTClient throw the properly-typed exception. Consider gating waitForIndexed on a value that reindex changes (e.g. a field or version bump) rather than polling for mere document presence, which can return stale pre-reindex results and cause test flakiness.

💡 Edge Case: waitForIndexed may pass on the stale pre-reindex doc

📄 openmetadata-ui/src/main/resources/ui/playwright/utils/reindex.ts:72-86 📄 openmetadata-ui/src/main/resources/ui/playwright/utils/reindex.ts:27-28

reindexEntities triggers the rebuild and then waitForIndexed polls the search alias until it sees exactly one hit for the id. The backend reindex deletes the doc and re-creates it, but if the endpoint returns before the async delete has run (the file's own comment states it is async — 'answers 202 and runs on the executor'), the first poll observes the still-present old document, returns 1, and resolves immediately — so the subsequent assertions can race the rebuild the specs exist to validate, giving false-green or flaky results. If the endpoint instead blocks until completion (it calls future.get(...)), the wait is simply redundant. Consider gating on a value the rebuild changes (e.g. poll a field/version that reindex updates, or delete-then-wait-for-reappear) rather than mere presence of any doc for the id.

✅ 1 resolved
Quality: Airflow API-detection failure now masks non-scheduler faults during delete

📄 openmetadata-service/src/main/java/org/openmetadata/service/clients/pipeline/airflow/AirflowRESTClient.java:698-710 📄 openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/IngestionPipelineRepository.java:826-840
getApiEndpointSegments() sits on the hot path of every Airflow operation (via buildURI), so changing it to throw IngestionRunnerUnavailableException broadens what deleteDeployedPipeline tolerates: detectAirflowApiVersion() returns null not only when the scheduler is unreachable but also when the OM plugin isn't installed, auth fails, or TLS is misconfigured. During a cascade or force delete (allowUnavailableRunner=true) all of these are now swallowed with only a warning, silently orphaning the DAG even when the root cause is a fixable misconfiguration rather than a transient outage. Consider distinguishing a genuine connectivity failure from plugin/auth errors before tolerating it, or at least ensure the logged warning captures the underlying cause so orphaned DAGs are diagnosable.

🤖 Prompt for agents
Code Review: Comprehensive optimization of the java-playwright-nightly CI pipeline that eliminates 30 minutes of test idle time, deduplicates 23 UIITs already covered by the Playwright suite, and restructures CI to parallelize image builds across shards. Fixes a production bug where cascade hard-deletes of services with ingestion pipelines fail when Airflow is unreachable by having `AirflowRESTClient` throw the properly-typed exception. Consider gating `waitForIndexed` on a value that reindex changes (e.g. a field or version bump) rather than polling for mere document presence, which can return stale pre-reindex results and cause test flakiness.

1. 💡 Edge Case: waitForIndexed may pass on the stale pre-reindex doc
   Files: openmetadata-ui/src/main/resources/ui/playwright/utils/reindex.ts:72-86, openmetadata-ui/src/main/resources/ui/playwright/utils/reindex.ts:27-28

   `reindexEntities` triggers the rebuild and then `waitForIndexed` polls the search alias until it sees exactly one hit for the id. The backend reindex deletes the doc and re-creates it, but if the endpoint returns before the async delete has run (the file's own comment states it is async — 'answers 202 and runs on the executor'), the first poll observes the still-present old document, returns 1, and resolves immediately — so the subsequent assertions can race the rebuild the specs exist to validate, giving false-green or flaky results. If the endpoint instead blocks until completion (it calls `future.get(...)`), the wait is simply redundant. Consider gating on a value the rebuild changes (e.g. poll a field/version that reindex updates, or delete-then-wait-for-reappear) rather than mere presence of any doc for the id.

Options

Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

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

Labels

backend safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

java-playwright-nightly takes ~84 min on every search-indexing PR

1 participant