fix: scope AJV instances per lintDocument call to fix concurrent validation#2774
Open
vlindhol wants to merge 1 commit intoRedocly:mainfrom
Open
fix: scope AJV instances per lintDocument call to fix concurrent validation#2774vlindhol wants to merge 1 commit intoRedocly:mainfrom
vlindhol wants to merge 1 commit intoRedocly:mainfrom
Conversation
🦋 Changeset detectedLatest commit: 1157188 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
75353fe to
4572e82
Compare
a0f6003 to
18bfbff
Compare
…dation The global AJV singleton in `ajv.ts` captured a `resolve` closure from whichever document first created the instance. When consumers like `openapi-typescript` process multiple APIs concurrently via `Promise.all`, the second document's `resolve` was silently discarded, producing spurious "Example validation errored: can't resolve reference" warnings for valid same-document `$ref`s. Replace the global singleton with an `AjvValidator` class instantiated per `lintDocument` call and threaded through WalkContext/UserContext.
18bfbff to
1157188
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The global AJV singleton in
packages/core/src/rules/ajv.tscaptured aresolveclosure from whichever document first created the instance. When consumers likeopenapi-typescriptprocess multiple APIs concurrently viaPromise.all(using@redocly/openapi-core'slintDocument), the second+ document'sresolvewas silently discarded. This produced spurious warnings:These warnings appeared for valid same-document
$refs that have anexample/examplessibling, but only when:Promise.alloverlintDocument)$refs (triggering AJV'sloadSchemaSync)The
redocly lintCLI was unaffected because it processes APIs sequentially.I did a similar PR (#2135) last year to fix the same thing but it got stale, and this time I managed to create a minimal test case to prove the bug exists.
Fix
AjvValidatorclass that encapsulates AJV instance cachinglintDocumentcall creates its ownAjvValidatorinstance, threaded throughWalkContext→UserContextChanges
packages/core/src/rules/ajv.ts— Refactored from free functions + global singleton to anAjvValidatorclass with avalidate()method and privategetAjv()/getValidator()methodspackages/core/src/walk.ts— AddedajvValidator: AjvValidatortoWalkContextandUserContext, threaded through all visitor context construction sitespackages/core/src/lint.ts— EachlintDocument/lintConfigcall createsnew AjvValidator()on the context (also removes the oldreleaseAjvInstance()call and its associated FIXME)packages/core/src/rules/utils.ts—validateExamplecallsctx.ajvValidator.validate()instead of the old free functionTest plan
lint()viaPromise.allon two specs with same-doc$ref+example+ cross-file$ref— confirmed it fails before the fix and passes after