@@ -9,6 +9,8 @@ use warp::{hyper, Rejection};
9
9
10
10
use arrow:: json:: writer:: record_batches_to_json_rows;
11
11
use arrow:: record_batch:: RecordBatch ;
12
+ #[ cfg( feature = "frontend-arrow-flight" ) ]
13
+ use arrow_flight:: flight_service_client:: FlightServiceClient ;
12
14
13
15
use arrow_integration_test:: { schema_from_json, schema_to_json} ;
14
16
use arrow_schema:: SchemaRef ;
@@ -42,9 +44,9 @@ use crate::auth::{token_to_principal, AccessPolicy, Action, UserContext};
42
44
use crate :: catalog:: DEFAULT_DB ;
43
45
#[ cfg( feature = "metrics" ) ]
44
46
use crate :: config:: context:: HTTP_REQUESTS ;
45
- use crate :: config:: schema:: { AccessSettings , MEBIBYTES } ;
47
+ use crate :: config:: schema:: { AccessSettings , HttpFrontend , MEBIBYTES } ;
46
48
use crate :: {
47
- config:: schema:: { str_to_hex_hash, HttpFrontend } ,
49
+ config:: schema:: str_to_hex_hash,
48
50
context:: logical:: { is_read_only, is_statement_read_only} ,
49
51
context:: SeafowlContext ,
50
52
} ;
@@ -482,8 +484,29 @@ async fn load_part(mut part: Part) -> Result<Vec<u8>, ApiError> {
482
484
Ok ( bytes)
483
485
}
484
486
485
- // We need the allow to silence the compiler: it asks us to add warp::generic::Tuple to the first
486
- // parameter of the return type, but that struct is not exportable (generic is private).
487
+ /// GET /healthz or /readyz
488
+ pub async fn health_endpoint ( context : Arc < SeafowlContext > ) -> Result < Response , ApiError > {
489
+ #[ cfg( feature = "frontend-arrow-flight" ) ]
490
+ if let Some ( flight) = & context. config . frontend . flight {
491
+ // TODO: run SELECT 1 or something similar?
492
+ if let Err ( err) = FlightServiceClient :: connect ( format ! (
493
+ "http://{}:{}" ,
494
+ flight. bind_host, flight. bind_port
495
+ ) )
496
+ . await
497
+ {
498
+ warn ! ( %err, "Arrow Flight client can't connect, health check failed" ) ;
499
+ return Ok ( warp:: reply:: with_status (
500
+ "not_ready" ,
501
+ StatusCode :: SERVICE_UNAVAILABLE ,
502
+ )
503
+ . into_response ( ) ) ;
504
+ } ;
505
+ } ;
506
+
507
+ Ok ( warp:: reply:: with_status ( "ready" , StatusCode :: OK ) . into_response ( ) )
508
+ }
509
+
487
510
pub fn filters (
488
511
context : Arc < SeafowlContext > ,
489
512
config : HttpFrontend ,
@@ -501,22 +524,34 @@ pub fn filters(
501
524
. max_age ( CORS_MAXAGE ) ;
502
525
503
526
let log = warp:: log:: custom ( |info : Info < ' _ > | {
527
+ let path = info. path ( ) ;
528
+
504
529
#[ cfg( feature = "metrics" ) ]
505
- counter ! (
506
- HTTP_REQUESTS ,
507
- "method" => info. method( ) . as_str( ) . to_string( ) ,
508
- // Omit a potential db prefix or url-encoded query from the path
509
- "route" => if info. path( ) . contains( "/upload/" ) { "/upload" } else { "/q" } ,
510
- "status" => info. status( ) . as_u16( ) . to_string( ) ,
511
- )
512
- . increment ( 1 ) ;
530
+ {
531
+ let route = if path. contains ( "/upload/" ) {
532
+ "/upload" . to_string ( )
533
+ } else if path. contains ( "/q" ) {
534
+ "/q" . to_string ( )
535
+ } else {
536
+ path. to_string ( )
537
+ } ;
538
+
539
+ counter ! (
540
+ HTTP_REQUESTS ,
541
+ "method" => info. method( ) . as_str( ) . to_string( ) ,
542
+ // Omit a potential db prefix or url-encoded query from the path
543
+ "route" => route,
544
+ "status" => info. status( ) . as_u16( ) . to_string( ) ,
545
+ )
546
+ . increment ( 1 ) ;
547
+ }
513
548
514
549
info ! (
515
550
target: module_path!( ) ,
516
551
"{} \" {} {} {:?}\" {} \" {}\" \" {}\" {:?}" ,
517
552
info. remote_addr( ) . map( |addr| addr. to_string( ) ) . unwrap_or( "-" . to_string( ) ) ,
518
553
info. method( ) ,
519
- info . path( ) ,
554
+ path,
520
555
info. version( ) ,
521
556
info. status( ) . as_u16( ) ,
522
557
info. referer( ) . unwrap_or( "-" ) ,
@@ -581,7 +616,7 @@ pub fn filters(
581
616
. map ( into_response) ;
582
617
583
618
// Upload endpoint
584
- let ctx = context;
619
+ let ctx = context. clone ( ) ;
585
620
let upload_route = warp:: path!( String / "upload" / String / String )
586
621
. or ( warp:: any ( )
587
622
. map ( move || DEFAULT_DB . to_string ( ) )
@@ -596,9 +631,21 @@ pub fn filters(
596
631
. then ( upload)
597
632
. map ( into_response) ;
598
633
634
+ // Health-check/readiness probe
635
+ let ctx = context;
636
+ let health_route = warp:: path!( "healthz" )
637
+ . or ( warp:: path!( "readyz" ) )
638
+ . and ( warp:: path:: end ( ) )
639
+ . and ( warp:: get ( ) )
640
+ . unify ( )
641
+ . and ( warp:: any ( ) . map ( move || ctx. clone ( ) ) )
642
+ . then ( health_endpoint)
643
+ . map ( into_response) ;
644
+
599
645
cached_read_query_route
600
646
. or ( uncached_read_write_query_route)
601
647
. or ( upload_route)
648
+ . or ( health_route)
602
649
. with ( cors)
603
650
. with ( log)
604
651
. map ( |r| with_header ( r, header:: VARY , VARY ) )
0 commit comments