@@ -9,8 +9,8 @@ use hyper::header::HeaderName;
99use rivet_guard_core:: { RouteConfig , RouteTarget , RoutingOutput , request_context:: RequestContext } ;
1010
1111use super :: {
12- SEC_WEBSOCKET_PROTOCOL , WS_PROTOCOL_ACTOR , WS_PROTOCOL_BYPASS_CONNECTABLE , WS_PROTOCOL_TOKEN ,
13- X_RIVET_BYPASS_CONNECTABLE , X_RIVET_TOKEN , actor_path:: ParsedActorPath ,
12+ SEC_WEBSOCKET_PROTOCOL , WS_PROTOCOL_ACTOR , WS_PROTOCOL_SKIP_READY_WAIT , WS_PROTOCOL_TOKEN ,
13+ X_RIVET_SKIP_READY_WAIT , X_RIVET_TOKEN , actor_path:: ParsedActorPath ,
1414} ;
1515use crate :: {
1616 errors,
@@ -70,22 +70,21 @@ pub async fn route_request_path_based_inner(
7070
7171 tracing:: debug!( ?actor_path, "routing using path-based actor routing" ) ;
7272
73- let ( actor_id, token, stripped_path, bypass_connectable ) = match actor_path {
73+ let ( actor_id, token, stripped_path, skip_ready_wait ) = match actor_path {
7474 ParsedActorPath :: Direct ( path) => (
7575 Id :: parse ( & path. actor_id ) . context ( "invalid actor id in path" ) ?,
7676 read_gateway_token_for_path_based ( req_ctx, path. token . as_deref ( ) ) ?
7777 . map ( ToOwned :: to_owned) ,
7878 path. stripped_path . clone ( ) ,
79- // TODO:
80- false ,
79+ read_skip_ready_wait_for_path_based ( req_ctx) ?,
8180 ) ,
8281 ParsedActorPath :: Query ( path) => match resolve_query ( ctx, & path. query ) . await ? {
8382 ResolveQueryActorResult :: Found { actor_id } => (
8483 actor_id,
8584 read_gateway_token_for_path_based ( req_ctx, path. token . as_deref ( ) ) ?
8685 . map ( ToOwned :: to_owned) ,
8786 path. stripped_path . clone ( ) ,
88- path. query . bypass_connectable ( ) ,
87+ path. query . skip_ready_wait ( ) ,
8988 ) ,
9089 ResolveQueryActorResult :: Forward { dc_label } => {
9190 let peer_dc = ctx
@@ -116,7 +115,7 @@ pub async fn route_request_path_based_inner(
116115 actor_id,
117116 & stripped_path,
118117 token. as_deref ( ) ,
119- bypass_connectable ,
118+ skip_ready_wait ,
120119 )
121120 . await
122121 . map ( Some )
@@ -148,7 +147,7 @@ pub async fn route_request(
148147 set_non_preflight_cors ( req_ctx) ;
149148
150149 // Extract actor ID and token from WebSocket protocol or HTTP headers
151- let ( actor_id_str, token, bypass_connectable ) = if req_ctx. is_websocket ( ) {
150+ let ( actor_id_str, token, skip_ready_wait ) = if req_ctx. is_websocket ( ) {
152151 // For WebSocket, parse the sec-websocket-protocol header
153152 let protocols_header = req_ctx
154153 . headers ( )
@@ -182,11 +181,11 @@ pub async fn route_request(
182181 . find_map ( |p| p. strip_prefix ( WS_PROTOCOL_TOKEN ) )
183182 . map ( ToOwned :: to_owned) ;
184183
185- let bypass_connectable = protocols
184+ let skip_ready_wait = protocols
186185 . iter ( )
187- . any ( |p| p == & WS_PROTOCOL_BYPASS_CONNECTABLE ) ;
186+ . any ( |p| p == & WS_PROTOCOL_SKIP_READY_WAIT ) ;
188187
189- ( actor_id, token, bypass_connectable )
188+ ( actor_id, token, skip_ready_wait )
190189 } else {
191190 // For HTTP, use headers
192191 let actor_id = req_ctx
@@ -210,9 +209,9 @@ pub async fn route_request(
210209 . context ( "invalid x-rivet-token header" ) ?
211210 . map ( ToOwned :: to_owned) ;
212211
213- let bypass_connectable = req_ctx . headers ( ) . contains_key ( X_RIVET_BYPASS_CONNECTABLE ) ;
212+ let skip_ready_wait = read_skip_ready_wait_header ( req_ctx ) ? ;
214213
215- ( actor_id. to_string ( ) , token, bypass_connectable )
214+ ( actor_id. to_string ( ) , token, skip_ready_wait )
216215 } ;
217216
218217 // Find actor to route to
@@ -226,7 +225,7 @@ pub async fn route_request(
226225 actor_id,
227226 & stripped_path,
228227 token. as_deref ( ) ,
229- bypass_connectable ,
228+ skip_ready_wait ,
230229 )
231230 . await
232231 . map ( Some )
@@ -247,7 +246,7 @@ async fn route_request_inner(
247246 actor_id : Id ,
248247 stripped_path : & str ,
249248 _token : Option < & str > ,
250- bypass_connectable : bool ,
249+ skip_ready_wait : bool ,
251250) -> Result < RoutingOutput > {
252251 // NOTE: Token validation implemented in EE
253252
@@ -323,7 +322,7 @@ async fn route_request_inner(
323322 actor_id,
324323 actor,
325324 stripped_path,
326- bypass_connectable ,
325+ skip_ready_wait ,
327326 ready_sub2,
328327 stopped_sub2,
329328 fail_sub2,
@@ -338,7 +337,7 @@ async fn route_request_inner(
338337 actor_id,
339338 actor,
340339 stripped_path,
341- bypass_connectable ,
340+ skip_ready_wait ,
342341 ready_sub,
343342 stopped_sub,
344343 fail_sub,
@@ -361,7 +360,7 @@ async fn handle_actor_v2(
361360 actor_id : Id ,
362361 actor : pegboard:: ops:: actor:: get_for_gateway:: Output ,
363362 stripped_path : & str ,
364- bypass_connectable : bool ,
363+ skip_ready_wait : bool ,
365364 mut ready_sub : SubscriptionHandle < pegboard:: workflows:: actor2:: Ready > ,
366365 mut stopped_sub : SubscriptionHandle < pegboard:: workflows:: actor2:: Stopped > ,
367366 mut fail_sub : SubscriptionHandle < pegboard:: workflows:: actor2:: Failed > ,
@@ -378,7 +377,7 @@ async fn handle_actor_v2(
378377 }
379378
380379 let envoy_key = if let ( Some ( envoy_key) , true ) =
381- ( actor. envoy_key , actor. connectable || bypass_connectable )
380+ ( actor. envoy_key , actor. connectable || skip_ready_wait )
382381 {
383382 envoy_key
384383 } else {
@@ -464,7 +463,7 @@ async fn handle_actor_v1(
464463 actor_id : Id ,
465464 actor : pegboard:: ops:: actor:: get_for_gateway:: Output ,
466465 stripped_path : & str ,
467- bypass_connectable : bool ,
466+ skip_ready_wait : bool ,
468467 mut ready_sub : SubscriptionHandle < pegboard:: workflows:: actor:: Ready > ,
469468 mut stopped_sub : SubscriptionHandle < pegboard:: workflows:: actor:: Stopped > ,
470469 mut fail_sub : SubscriptionHandle < pegboard:: workflows:: actor:: Failed > ,
@@ -490,7 +489,7 @@ async fn handle_actor_v1(
490489 }
491490
492491 let runner_id = if let ( Some ( runner_id) , true ) =
493- ( actor. runner_id , actor. connectable || bypass_connectable )
492+ ( actor. runner_id , actor. connectable || skip_ready_wait )
494493 {
495494 runner_id
496495 } else {
@@ -555,7 +554,7 @@ async fn handle_actor_v1(
555554 actor_id,
556555 actor,
557556 stripped_path,
558- bypass_connectable ,
557+ skip_ready_wait ,
559558 ready_sub2,
560559 stopped_sub2,
561560 fail_sub2,
@@ -626,6 +625,46 @@ fn read_gateway_token_for_path_based<'a>(
626625 }
627626}
628627
628+ fn read_skip_ready_wait_for_path_based ( req_ctx : & RequestContext ) -> Result < bool > {
629+ if req_ctx. is_websocket ( ) {
630+ Ok ( req_ctx
631+ . headers ( )
632+ . get ( SEC_WEBSOCKET_PROTOCOL )
633+ . and_then ( |protocols| protocols. to_str ( ) . ok ( ) )
634+ . is_some_and ( |protocols| {
635+ protocols
636+ . split ( ',' )
637+ . map ( |p| p. trim ( ) )
638+ . any ( |p| p == WS_PROTOCOL_SKIP_READY_WAIT )
639+ } ) )
640+ } else {
641+ read_skip_ready_wait_header ( req_ctx)
642+ }
643+ }
644+
645+ fn read_skip_ready_wait_header ( req_ctx : & RequestContext ) -> Result < bool > {
646+ let Some ( value) = req_ctx. headers ( ) . get ( X_RIVET_SKIP_READY_WAIT ) else {
647+ return Ok ( false ) ;
648+ } ;
649+
650+ let value = value. to_str ( ) . context ( "invalid x-rivet-skip-ready-wait header" ) ?;
651+ parse_skip_ready_wait_bool ( value) . ok_or_else ( || {
652+ crate :: errors:: InvalidHeader {
653+ header : X_RIVET_SKIP_READY_WAIT . to_string ( ) ,
654+ detail : "expected true, false, 1, or 0" . to_string ( ) ,
655+ }
656+ . build ( )
657+ } )
658+ }
659+
660+ fn parse_skip_ready_wait_bool ( value : & str ) -> Option < bool > {
661+ match value {
662+ "true" | "1" => Some ( true ) ,
663+ "false" | "0" => Some ( false ) ,
664+ _ => None ,
665+ }
666+ }
667+
629668/// Waits for initial delay, then periodically checks for runner pool errors.
630669///
631670/// Returns `true` if the pool has an active error, `false` otherwise.
0 commit comments