Skip to content

fix(restheart-mongo): deterministic GraphQL app cache + expires_in noise#142

Open
slayerjain wants to merge 1 commit into
mainfrom
fix/restheart-determinism
Open

fix(restheart-mongo): deterministic GraphQL app cache + expires_in noise#142
slayerjain wants to merge 1 commit into
mainfrom
fix/restheart-determinism

Conversation

@slayerjain

Copy link
Copy Markdown
Member

The keploy restheart-mongo CI lane flaked on two recorded fields; both are app/JWT non-determinism, fixed the same way the lane already handles the ACL cache and the access_token JWT.

1. post-graphql-halpeople — Mongo mock-miss → 500 MongoSocketReadException

RESTHeart's GraphQL service caches gql-apps app definitions with a 60s time-to-revalidate (app-cache-ttr, Caffeine nanoTime ticker) — the exact same time-freeze × cache-ttl interaction already documented and fixed for /mongoAclAuthorizer. Under keploy test --freezeTime the ticker is frozen, so the app cache never revalidates and RESTHeart issues a different number/order of find gql-apps mongo queries than were recorded. The unmatched find has no recorded mock, so keploy's mongo proxy closes the socket and RESTHeart returns 500 instead of the recorded response.

Fix: add /graphql/app-cache-enabled->false to RHO so gql-apps is read-through on every request (identical mongo stream at record & replay), mirroring the existing /mongoAclAuthorizer/cache-enabled->false.

2. post-tokenexpires_in 872 vs 871

/tokens returns expires_in = exp - now computed at request time; it can differ by 1s across record/replay when the request straddles a second boundary, even under --freezeTime. The JWT (access_token) is already noised; add expires_in for the same reason.

Validated against keploy/enterprise #2075 (restheart-linux lane pinned to this branch).

The keploy restheart-mongo lane flaked on two recorded fields; both are
app/JWT non-determinism, fixed the same way the lane already handles the
ACL cache and the access_token JWT:

1. post-graphql-halpeople (mongo mock-miss -> 500 MongoSocketReadException):
   RESTHeart's GraphQL service caches gql-apps app definitions with a 60s
   time-to-revalidate (app-cache-ttr, Caffeine nanoTime ticker) — the exact
   same time-freeze x cache-ttl interaction already documented for
   /mongoAclAuthorizer. Under `keploy test --freezeTime` the ticker is
   frozen, so the app cache never revalidates and RESTHeart issues a
   different number/order of `find gql-apps` mongo queries than were
   recorded; the unmatched find has no mock so keploy's mongo proxy closes
   the socket and RESTHeart returns 500 instead of the recorded response.
   Fix: add /graphql/app-cache-enabled->false to RHO so gql-apps is
   read-through every request (identical mongo stream at record & replay),
   mirroring the existing /mongoAclAuthorizer/cache-enabled->false.

2. post-token (expires_in 872 vs 871): /tokens returns expires_in =
   seconds-until-exp computed at request time; it can differ by 1s across
   record/replay when the request straddles a second boundary, even under
   --freezeTime. The JWT itself (access_token) is already noised; add
   expires_in to globalNoise.body for the same reason.

Signed-off-by: Shubham Jain <shubham@keploy.io>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: slayerjain <shubham@keploy.io>
Copilot AI review requested due to automatic review settings June 8, 2026 05:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR reduces Keploy record/replay flakiness in the restheart-mongo sample by removing two sources of non-determinism: RESTHeart GraphQL app-definition caching (which interacts poorly with --freezeTime) and the 1s jitter in the OAuth expires_in countdown.

Changes:

  • Disable RESTHeart GraphQL app-definition caching via RHO (/graphql/app-cache-enabled->false) to keep Mongo query streams consistent between record and replay.
  • Treat /token response field expires_in as noise in Keploy config, matching the existing approach for JWT fields.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
restheart-mongo/keploy.yml.template Adds expires_in to global noise fields to avoid replay mismatches from time-derived countdown values.
restheart-mongo/docker-compose.yml Disables GraphQL app cache through RHO and documents the --freezeTime × cache-TTR interaction causing mongo mock misses.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

client_ip: []
latencyMs: []
access_token: []
# RESTHeart's /tokens endpoint returns expires_in = seconds until
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

restheart-mongo sample coverage

ref coverage
base (main) 0.0%
this PR 53.1%

Threshold: PR may not drop coverage by more than 1.0pp. Override per-repo via the RESTHEART_COVERAGE_THRESHOLD actions variable.

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