@@ -24,10 +24,23 @@ import {typeString} from './util/typeString'
24
24
import { unknownFieldsValidator } from './validators/unknownFieldsValidator'
25
25
26
26
// this is the number of requests allowed inflight at once. this is done to prevent
27
- // the validation library from overwhelming our backend
28
- const MAX_FETCH_CONCURRENCY = 10
29
-
30
- const limitConcurrency = createClientConcurrencyLimiter ( MAX_FETCH_CONCURRENCY )
27
+ // the validation library from overwhelming our backend.
28
+ // NOTE: this was upped from 10 to prevent issues where many concurrency
29
+ // `client.fetch` requests would "clog" custom validators from finishing due to
30
+ // not enough concurrent requests being fulfilled
31
+ //
32
+ // NOTE: ensure to update the TSDoc and CLI help test if this is changed
33
+ const DEFAULT_MAX_FETCH_CONCURRENCY = 25
34
+
35
+ // NOTE: ensure to update the TSDoc and CLI help test if this is changed
36
+ const DEFAULT_MAX_CUSTOM_VALIDATION_CONCURRENCY = 5
37
+
38
+ let _limitConcurrency : ReturnType < typeof createClientConcurrencyLimiter > | undefined
39
+ const getConcurrencyLimiter = ( maxConcurrency : number ) => {
40
+ if ( _limitConcurrency ) return _limitConcurrency
41
+ _limitConcurrency = createClientConcurrencyLimiter ( maxConcurrency )
42
+ return _limitConcurrency
43
+ }
31
44
32
45
const isRecord = ( maybeRecord : unknown ) : maybeRecord is Record < string , unknown > =>
33
46
typeof maybeRecord === 'object' && maybeRecord !== null && ! Array . isArray ( maybeRecord )
@@ -104,8 +117,21 @@ export interface ValidateDocumentOptions {
104
117
* concurrently at once. This helps prevent custom validators from
105
118
* overwhelming backend services (e.g. called via fetch) used in async,
106
119
* user-defined validation functions. (i.e. `rule.custom(async() => {})`)
120
+ *
121
+ * Note that lowering this number may also help in cases where a custom
122
+ * validator could potentially exhaust the fetch concurrency. This is 5 by
123
+ * default.
107
124
*/
108
125
maxCustomValidationConcurrency ?: number
126
+
127
+ /**
128
+ * The amount of allowed inflight fetch requests at once. You may need to up
129
+ * this value if you have complex custom validations that require many
130
+ * `client.fetch` requests at once. It's possible for custom validator to
131
+ * stall if there are not enough concurrent fetch requests available to
132
+ * fullfil the custom validation. This is 25 by default.
133
+ */
134
+ maxFetchConcurrency ?: number
109
135
}
110
136
111
137
/**
@@ -118,9 +144,13 @@ export function validateDocument({
118
144
document,
119
145
workspace,
120
146
environment = 'studio' ,
147
+ maxFetchConcurrency,
121
148
...options
122
149
} : ValidateDocumentOptions ) : Promise < ValidationMarker [ ] > {
123
150
const getClient = options . getClient || workspace . getClient
151
+ const limitConcurrency = getConcurrencyLimiter (
152
+ maxFetchConcurrency ?? DEFAULT_MAX_FETCH_CONCURRENCY ,
153
+ )
124
154
const getConcurrencyLimitedClient = ( clientOptions : SourceClientOptions ) =>
125
155
limitConcurrency ( getClient ( clientOptions ) )
126
156
@@ -190,8 +220,10 @@ export function validateDocumentObservable({
190
220
}
191
221
192
222
let customValidationConcurrencyLimiter = customValidationConcurrencyLimiters . get ( schema )
193
- if ( ! customValidationConcurrencyLimiter && maxCustomValidationConcurrency ) {
194
- customValidationConcurrencyLimiter = new ConcurrencyLimiter ( maxCustomValidationConcurrency )
223
+ if ( ! customValidationConcurrencyLimiter ) {
224
+ customValidationConcurrencyLimiter = new ConcurrencyLimiter (
225
+ maxCustomValidationConcurrency ?? DEFAULT_MAX_CUSTOM_VALIDATION_CONCURRENCY ,
226
+ )
195
227
customValidationConcurrencyLimiters . set ( schema , customValidationConcurrencyLimiter )
196
228
}
197
229
0 commit comments