@@ -19,9 +19,10 @@ use common::{
19
19
identity:: InertIdentity ,
20
20
knobs:: {
21
21
APPLICATION_FUNCTION_RUNNER_SEMAPHORE_TIMEOUT ,
22
- APPLICATION_MAX_CONCURRENT_ACTIONS ,
23
22
APPLICATION_MAX_CONCURRENT_MUTATIONS ,
23
+ APPLICATION_MAX_CONCURRENT_NODE_ACTIONS ,
24
24
APPLICATION_MAX_CONCURRENT_QUERIES ,
25
+ APPLICATION_MAX_CONCURRENT_V8_ACTIONS ,
25
26
ISOLATE_MAX_USER_HEAP_SIZE ,
26
27
UDF_EXECUTOR_OCC_INITIAL_BACKOFF ,
27
28
UDF_EXECUTOR_OCC_MAX_BACKOFF ,
@@ -225,16 +226,19 @@ impl<RT: Runtime> FunctionRouter<RT> {
225
226
database,
226
227
system_env_vars,
227
228
query_limiter : Arc :: new ( Limiter :: new (
229
+ ModuleEnvironment :: Isolate ,
228
230
UdfType :: Query ,
229
231
* APPLICATION_MAX_CONCURRENT_QUERIES ,
230
232
) ) ,
231
233
mutation_limiter : Arc :: new ( Limiter :: new (
234
+ ModuleEnvironment :: Isolate ,
232
235
UdfType :: Mutation ,
233
236
* APPLICATION_MAX_CONCURRENT_MUTATIONS ,
234
237
) ) ,
235
238
action_limiter : Arc :: new ( Limiter :: new (
239
+ ModuleEnvironment :: Isolate ,
236
240
UdfType :: Action ,
237
- * APPLICATION_MAX_CONCURRENT_ACTIONS ,
241
+ * APPLICATION_MAX_CONCURRENT_V8_ACTIONS ,
238
242
) ) ,
239
243
}
240
244
}
@@ -255,7 +259,8 @@ impl<RT: Runtime> FunctionRouter<RT> {
255
259
context : ExecutionContext ,
256
260
) -> anyhow:: Result < ( Transaction < RT > , FunctionOutcome ) > {
257
261
anyhow:: ensure!( udf_type == UdfType :: Query || udf_type == UdfType :: Mutation ) ;
258
- let timer = function_total_timer ( udf_type) ;
262
+ // All queries and mutations are run in the isolate environment.
263
+ let timer = function_total_timer ( ModuleEnvironment :: Isolate , udf_type) ;
259
264
let ( tx, outcome) = self
260
265
. function_runner_execute ( tx, path_and_args, udf_type, journal, context, None )
261
266
. await ?;
@@ -271,7 +276,6 @@ impl<RT: Runtime> FunctionRouter<RT> {
271
276
log_line_sender : mpsc:: UnboundedSender < LogLine > ,
272
277
context : ExecutionContext ,
273
278
) -> anyhow:: Result < ActionOutcome > {
274
- let timer = function_total_timer ( UdfType :: Action ) ;
275
279
let ( _, outcome) = self
276
280
. function_runner_execute (
277
281
tx,
@@ -289,11 +293,10 @@ impl<RT: Runtime> FunctionRouter<RT> {
289
293
outcome
290
294
)
291
295
} ;
292
- timer. finish ( ) ;
293
296
Ok ( outcome)
294
297
}
295
298
296
- // Execute using the function runner. Can be used for all Udf types including
299
+ // Execute using the function runner. Can be used for v8 udfs other than http
297
300
// actions.
298
301
async fn function_runner_execute (
299
302
& self ,
@@ -316,17 +319,9 @@ impl<RT: Runtime> FunctionRouter<RT> {
316
319
UdfType :: Action => & self . action_limiter ,
317
320
UdfType :: HttpAction => anyhow:: bail!( "Function runner does not support http actions" ) ,
318
321
} ;
319
- let mut request_guard = limiter. start ( ) ;
320
- select_biased ! {
321
- _ = request_guard. acquire_permit( ) . fuse( ) => { } ,
322
- _ = self . rt. wait( * APPLICATION_FUNCTION_RUNNER_SEMAPHORE_TIMEOUT ) => {
323
- log_function_wait_timeout( udf_type) ;
324
- anyhow:: bail!( ErrorMetadata :: overloaded(
325
- "TooManyConcurrentRequests" ,
326
- "Too many concurrent requests, backoff and try again." ,
327
- ) ) ;
328
- } ,
329
- }
322
+
323
+ let request_guard = limiter. acquire_permit_with_timeout ( & self . rt ) . await ?;
324
+
330
325
let timer = function_run_timer ( udf_type) ;
331
326
let ( function_tx, outcome, usage_stats) = self
332
327
. function_runner
@@ -384,6 +379,7 @@ impl<RT: Runtime> FunctionRouter<RT> {
384
379
// and log gauges for the number of waiting and currently running functions.
385
380
struct Limiter {
386
381
udf_type : UdfType ,
382
+ env : ModuleEnvironment ,
387
383
388
384
// Used to limit running functions.
389
385
semaphore : Semaphore ,
@@ -394,9 +390,10 @@ struct Limiter {
394
390
}
395
391
396
392
impl Limiter {
397
- fn new ( udf_type : UdfType , total_permits : usize ) -> Self {
393
+ fn new ( env : ModuleEnvironment , udf_type : UdfType , total_permits : usize ) -> Self {
398
394
let limiter = Self {
399
395
udf_type,
396
+ env,
400
397
semaphore : Semaphore :: new ( total_permits) ,
401
398
total_permits,
402
399
total_outstanding : AtomicUsize :: new ( 0 ) ,
@@ -406,6 +403,24 @@ impl Limiter {
406
403
limiter
407
404
}
408
405
406
+ async fn acquire_permit_with_timeout < ' a , RT : Runtime > (
407
+ & ' a self ,
408
+ rt : & ' a RT ,
409
+ ) -> anyhow:: Result < RequestGuard < ' a > > {
410
+ let mut request_guard = self . start ( ) ;
411
+ select_biased ! {
412
+ _ = request_guard. acquire_permit( ) . fuse( ) => { } ,
413
+ _ = rt. wait( * APPLICATION_FUNCTION_RUNNER_SEMAPHORE_TIMEOUT ) => {
414
+ log_function_wait_timeout( self . env, self . udf_type) ;
415
+ anyhow:: bail!( ErrorMetadata :: overloaded(
416
+ "TooManyConcurrentRequests" ,
417
+ "Too many concurrent requests, backoff and try again." ,
418
+ ) ) ;
419
+ } ,
420
+ }
421
+ Ok ( request_guard)
422
+ }
423
+
409
424
fn start ( & self ) -> RequestGuard {
410
425
self . total_outstanding . fetch_add ( 1 , Ordering :: SeqCst ) ;
411
426
// Update the gauge to account for the newly waiting request.
@@ -423,8 +438,18 @@ impl Limiter {
423
438
. total_outstanding
424
439
. load ( Ordering :: SeqCst )
425
440
. saturating_sub ( running) ;
426
- log_outstanding_functions ( running, self . udf_type , OutstandingFunctionState :: Running ) ;
427
- log_outstanding_functions ( waiting, self . udf_type , OutstandingFunctionState :: Waiting ) ;
441
+ log_outstanding_functions (
442
+ running,
443
+ self . env ,
444
+ self . udf_type ,
445
+ OutstandingFunctionState :: Running ,
446
+ ) ;
447
+ log_outstanding_functions (
448
+ waiting,
449
+ self . env ,
450
+ self . udf_type ,
451
+ OutstandingFunctionState :: Waiting ,
452
+ ) ;
428
453
}
429
454
}
430
455
@@ -463,6 +488,11 @@ impl<'a> Drop for RequestGuard<'a> {
463
488
}
464
489
}
465
490
491
+ /// Executes UDFs for backends.
492
+ ///
493
+ /// This struct directly executes http and node actions. Queries, Mutations and
494
+ /// v8 Actions are instead routed through the FunctionRouter and its
495
+ /// FunctionRunner implementation.
466
496
pub struct ApplicationFunctionRunner < RT : Runtime > {
467
497
runtime : RT ,
468
498
pub ( crate ) database : Database < RT > ,
@@ -480,6 +510,7 @@ pub struct ApplicationFunctionRunner<RT: Runtime> {
480
510
481
511
cache_manager : CacheManager < RT > ,
482
512
system_env_vars : BTreeMap < EnvVarName , EnvVarValue > ,
513
+ node_action_limiter : Limiter ,
483
514
}
484
515
485
516
impl < RT : Runtime > HeapSize for ApplicationFunctionRunner < RT > {
@@ -529,6 +560,11 @@ impl<RT: Runtime> ApplicationFunctionRunner<RT> {
529
560
function_log,
530
561
cache_manager,
531
562
system_env_vars,
563
+ node_action_limiter : Limiter :: new (
564
+ ModuleEnvironment :: Node ,
565
+ UdfType :: Action ,
566
+ * APPLICATION_MAX_CONCURRENT_NODE_ACTIONS ,
567
+ ) ,
532
568
}
533
569
}
534
570
@@ -1072,6 +1108,8 @@ impl<RT: Runtime> ApplicationFunctionRunner<RT> {
1072
1108
. await ?
1073
1109
. context ( "Missing a valid module_version" ) ?;
1074
1110
let ( log_line_sender, log_line_receiver) = mpsc:: unbounded ( ) ;
1111
+
1112
+ let timer = function_total_timer ( module_version. environment , UdfType :: Action ) ;
1075
1113
match module_version. environment {
1076
1114
ModuleEnvironment :: Isolate => {
1077
1115
// TODO: This is the only use case of clone. We should get rid of clone,
@@ -1098,6 +1136,7 @@ impl<RT: Runtime> ApplicationFunctionRunner<RT> {
1098
1136
let memory_in_mb: u64 = ( * ISOLATE_MAX_USER_HEAP_SIZE / ( 1 << 20 ) )
1099
1137
. try_into ( )
1100
1138
. unwrap ( ) ;
1139
+ timer. finish ( ) ;
1101
1140
Ok ( ActionCompletion {
1102
1141
outcome,
1103
1142
execution_time : start. elapsed ( ) ,
@@ -1110,6 +1149,10 @@ impl<RT: Runtime> ApplicationFunctionRunner<RT> {
1110
1149
} )
1111
1150
} ,
1112
1151
ModuleEnvironment :: Node => {
1152
+ let _request_guard = self
1153
+ . node_action_limiter
1154
+ . acquire_permit_with_timeout ( & self . runtime )
1155
+ . await ?;
1113
1156
let mut source_maps = BTreeMap :: new ( ) ;
1114
1157
if let Some ( source_map) = module_version. source_map . clone ( ) {
1115
1158
source_maps. insert ( name. module ( ) . clone ( ) , source_map) ;
@@ -1204,6 +1247,7 @@ impl<RT: Runtime> ApplicationFunctionRunner<RT> {
1204
1247
syscall_trace : node_outcome. syscall_trace ,
1205
1248
udf_server_version,
1206
1249
} ;
1250
+ timer. finish ( ) ;
1207
1251
let memory_in_mb = node_outcome. memory_used_in_mb ;
1208
1252
Ok ( ActionCompletion {
1209
1253
outcome,
0 commit comments