Skip to content

UNOMI-964: Fix flaky GraphQLListIT via live condition-type resolution - #827

Merged
sergehuber merged 6 commits into
masterfrom
UNOMI-964-graphql-condition-factory-flake
Jul 16, 2026
Merged

UNOMI-964: Fix flaky GraphQLListIT via live condition-type resolution#827
sergehuber merged 6 commits into
masterfrom
UNOMI-964-graphql-condition-factory-flake

Conversation

@sergehuber

Copy link
Copy Markdown
Contributor

Summary

Fixes UNOMI-964: GraphQLListIT.testCRUD fails intermittently (locally and in CI) because the GraphQL condition factories are lazy static singletons. The base ConditionFactory snapshots definitionsService.getAllConditionTypes() once into conditionTypesMap and never refreshes it.

Under PaxExam @PerSuite, that snapshot is frozen for the whole container, captured at the first get() call. If that happens before the condition-type cache is warm, getConditionType("profilePropertyCondition") returns null, so the active-member query becomes a structural match-none for the rest of the run:

TypeResolutionServiceImpl: Condition has no type ID for query builder
ConditionESQueryBuilderDispatcher: Condition type is null for condition typeID=null, returning match-none query

findLists.totalCount == 1 still passes (fresh factory), while active.edges is always empty (stale singleton). This is a structural match-none, not an indexing delay — which is why prior timing-based fixes (deferred refreshPersistence, tripled retries) never worked.

Changes

  • Remove the static singletons from ProfileConditionFactory, EventConditionFactory, ProfileAliasConditionFactory, TopicConditionFactory; return a fresh instance per get().
  • Drop the conditionTypesMap snapshot in ConditionFactory; resolve types live via DefinitionsService.getConditionType(id). Also removes the retained first-request DataFetchingEnvironment/ServiceManager.
  • Harden AddProfileToListCommand: (send(event) & PROFILE_UPDATED) == PROFILE_UPDATED instead of exact equality (latent bitmask bug on the same code path).
  • Revert the misleading timing workarounds and comment in GraphQLListIT.testCRUD.
  • Add unit tests: live condition-type resolution, no-snapshot constructor, fresh-per-get() factories, and AddProfileToListCommand bitmask handling.

Performance

Negligible. All condition-type lookups are in-memory cache reads (no ES/IO). Net-positive: removes a synchronized static bottleneck and per-container memory retention. The high-frequency ingestion path (/context.json, /eventcollector, rule/segment evaluation) does not use these factories and is unaffected.

Test plan

  • mvn -pl graphql/cxs-impl test -Dtest=ConditionFactoryTest,AddProfileToListCommandTest — 10/10 pass.
  • graphql/cxs-impl compiles; itests test-compiles.
  • GraphQLListIT.testCRUD passes reliably (e.g. 20 consecutive local runs on the Elasticsearch profile).
  • No recurring returning match-none query warnings during the run.
  • Full graphql IT package is green.

sergehuber and others added 6 commits July 15, 2026 10:26
The GraphQL condition factories (Profile/Event/ProfileAlias/Topic) were lazy
static singletons whose base ConditionFactory snapshotted getAllConditionTypes()
once. Under PaxExam @persuite that snapshot was frozen for the whole container,
captured at first get(); if taken before the condition-type cache was warm,
getConditionType("profilePropertyCondition") returned null, producing a
match-none active-member query for the rest of the run. This is why prior
timing-based fixes never worked.

- Remove the static singletons; return a fresh factory instance per get().
- Drop the conditionTypesMap snapshot; resolve types live via
  DefinitionsService.getConditionType(id). Also removes the retained
  first-request DataFetchingEnvironment/ServiceManager.
- Harden AddProfileToListCommand: use (send(event) & PROFILE_UPDATED) ==
  PROFILE_UPDATED instead of exact equality (latent bitmask bug).
- Revert the misleading timing workarounds/comment in GraphQLListIT.testCRUD
  (deferred refresh + tripled retries).
- Add unit tests for live condition-type resolution, fresh-per-get factories,
  and the AddProfileToListCommand bitmask handling.
…ug in RemoveProfileFromListCommand

AddProfileToListCommand's PROFILE_UPDATED bitmask fix could silently save a
profile even when EventService.send() also reported an ERROR bit from a
nested event failure; log a warning in that case, matching the REST layer's
existing convention. RemoveProfileFromListCommand had the same pre-existing
exact-equality bitmask bug (`== PROFILE_UPDATED`) fixed in the original
UNOMI-964 commit but was left untouched; apply the identical fix and add
unit test coverage (previously untested).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Skip the unconditional mvn clean so looping a single integration test
can reuse the previous reactor install. Default behavior is unchanged.
…clusters

Instrument match-none condition collapse, empty list-member queries, and
rollover/ILM attachment so CI logs can pin whether flakes are tenant/context,
definitions-cache, or index-lifecycle related.
Time getMatchingRules against a large synthetic event-type ruleset instead
of full eventService.send in PaxExam, so the optimization signal is stable
and no longer fails CI on environmental noise.
…nectionDataFetcher

An empty active-members result is a legitimate, common production state (a
newly created list, or any list with no currently-active members), so emitting
a WARN-level [unomi-diag] line on every such query polluted production logs.
Remove the diagnostic, its helper, and the now-unused imports/logger; the
es/os-match-none dispatcher diagnostics still cover the genuinely anomalous path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sergehuber
sergehuber merged commit d4b57f0 into master Jul 16, 2026
6 checks passed
@sergehuber
sergehuber deleted the UNOMI-964-graphql-condition-factory-flake branch July 16, 2026 07:35
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.

1 participant