@@ -209,6 +209,34 @@ impl ConfigValidator {
209209 } ) ;
210210 }
211211 }
212+ PolicyConfig :: Bucket {
213+ balance_abs_threshold : _,
214+ balance_rel_threshold,
215+ bucket_adjust_interval_secs,
216+ } => {
217+ if * balance_rel_threshold < 1.0 {
218+ return Err ( ConfigError :: InvalidValue {
219+ field : "balance_rel_threshold" . to_string ( ) ,
220+ value : balance_rel_threshold. to_string ( ) ,
221+ reason : "Must be >= 1.0" . to_string ( ) ,
222+ } ) ;
223+ }
224+
225+ if * bucket_adjust_interval_secs < 1 {
226+ return Err ( ConfigError :: InvalidValue {
227+ field : "bucket_adjust_interval_secs" . to_string ( ) ,
228+ value : bucket_adjust_interval_secs. to_string ( ) ,
229+ reason : "Must be >= 1s" . to_string ( ) ,
230+ } ) ;
231+ }
232+ if * bucket_adjust_interval_secs >= 4294967296 {
233+ return Err ( ConfigError :: InvalidValue {
234+ field : "bucket_adjust_interval_secs" . to_string ( ) ,
235+ value : bucket_adjust_interval_secs. to_string ( ) ,
236+ reason : "Must be < 4294967296s" . to_string ( ) ,
237+ } ) ;
238+ }
239+ }
212240 }
213241 Ok ( ( ) )
214242 }
@@ -505,6 +533,13 @@ impl ConfigValidator {
505533 } ) ;
506534 }
507535 }
536+
537+ // Check bucket for decode
538+ if let Some ( PolicyConfig :: Bucket { .. } ) = decode_policy {
539+ return Err ( ConfigError :: IncompatibleConfig {
540+ reason : "Decode policy should not be allowed to be bucket" . to_string ( ) ,
541+ } ) ;
542+ }
508543 }
509544 }
510545
@@ -792,6 +827,67 @@ mod tests {
792827 }
793828 }
794829
830+ #[ test]
831+ fn test_validate_pd_mode_bucket_policy_restrictions ( ) {
832+ let config = RouterConfig :: new (
833+ RoutingMode :: PrefillDecode {
834+ prefill_urls : vec ! [
835+ ( "http://prefill1:8000" . to_string( ) , None ) ,
836+ ( "http://prefill2:8000" . to_string( ) , None ) ,
837+ ] ,
838+ decode_urls : vec ! [
839+ "http://decode1:8000" . to_string( ) ,
840+ "http://decode2:8000" . to_string( ) ,
841+ ] ,
842+ prefill_policy : Some ( PolicyConfig :: Bucket {
843+ balance_abs_threshold : 32 ,
844+ balance_rel_threshold : 1.1 ,
845+ bucket_adjust_interval_secs : 5 ,
846+ } ) ,
847+ decode_policy : Some ( PolicyConfig :: PowerOfTwo {
848+ load_check_interval_secs : 60 ,
849+ } ) ,
850+ } ,
851+ PolicyConfig :: Random , // Main policy as fallback
852+ ) ;
853+
854+ let result = ConfigValidator :: validate ( & config) ;
855+ assert ! (
856+ result. is_ok( ) ,
857+ "Prefill policy should be allowed to be bucket"
858+ ) ;
859+
860+ let config = RouterConfig :: new (
861+ RoutingMode :: PrefillDecode {
862+ prefill_urls : vec ! [
863+ ( "http://prefill1:8000" . to_string( ) , None ) ,
864+ ( "http://prefill2:8000" . to_string( ) , None ) ,
865+ ] ,
866+ decode_urls : vec ! [
867+ "http://decode1:8000" . to_string( ) ,
868+ "http://decode2:8000" . to_string( ) ,
869+ ] ,
870+ prefill_policy : Some ( PolicyConfig :: Bucket {
871+ balance_abs_threshold : 32 ,
872+ balance_rel_threshold : 1.1 ,
873+ bucket_adjust_interval_secs : 5 ,
874+ } ) ,
875+ decode_policy : Some ( PolicyConfig :: Bucket {
876+ balance_abs_threshold : 32 ,
877+ balance_rel_threshold : 1.1 ,
878+ bucket_adjust_interval_secs : 5 ,
879+ } ) ,
880+ } ,
881+ PolicyConfig :: Random , // Main policy as fallback
882+ ) ;
883+
884+ let result = ConfigValidator :: validate ( & config) ;
885+ assert ! (
886+ result. is_err( ) ,
887+ "Decode policy should not be allowed to be bucket"
888+ ) ;
889+ }
890+
795891 #[ test]
796892 fn test_validate_grpc_requires_tokenizer ( ) {
797893 let mut config = RouterConfig :: new (
0 commit comments