@@ -22,7 +22,7 @@ mod matcher;
2222const CHECKPOINT_MAILBOX_SIZE : usize = 1024 ;
2323const MAILBOX_SIZE : usize = 128 ;
2424const SUBSCRIPTION_CHANNEL_SIZE : usize = 256 ;
25- const MAX_SUBSCRIBERS : usize = 1024 ;
25+ const DEFAULT_MAX_SUBSCRIBERS : usize = 1024 ;
2626/// Bound on each shard task's mailbox (registrations, checkpoint fan-out,
2727/// and lag teardowns from the dispatcher).
2828const SHARD_MAILBOX_SIZE : usize = 64 ;
@@ -295,6 +295,8 @@ pub struct SubscriptionService {
295295 /// Filtered-subscriber counts per key space, shared with the shards;
296296 /// gates per-checkpoint key extraction.
297297 counters : Arc < SubscriberCounts > ,
298+ /// Global admission limit across all shards.
299+ max_subscribers : usize ,
298300
299301 // When set, delivery of a checkpoint waits until the index has committed
300302 // it (see [`IndexedCheckpointFn`]). `None` preserves the immediate-delivery
@@ -305,12 +307,14 @@ pub struct SubscriptionService {
305307}
306308
307309impl SubscriptionService {
308- /// `None` defaults `watermark_interval` to 25 checkpoints and `shards` to
309- /// the host's available parallelism, with a minimum of one.
310+ /// `None` defaults `watermark_interval` to 25 checkpoints,
311+ /// `max_subscribers` to 1024, and `shards` to the host's available
312+ /// parallelism, with a minimum of one shard.
310313 pub fn build (
311314 registry : & prometheus:: Registry ,
312315 indexed_checkpoint : Option < IndexedCheckpointFn > ,
313316 watermark_interval : Option < u32 > ,
317+ max_subscribers : Option < usize > ,
314318 shards : Option < u32 > ,
315319 ) -> (
316320 broadcast:: Sender < Arc < Checkpoint > > ,
@@ -321,6 +325,7 @@ impl SubscriptionService {
321325 let ( subscription_request_sender, mailbox) = mpsc:: channel ( MAILBOX_SIZE ) ;
322326
323327 let counters = Arc :: new ( SubscriberCounts :: default ( ) ) ;
328+ let max_subscribers = max_subscribers. unwrap_or ( DEFAULT_MAX_SUBSCRIBERS ) ;
324329 let watermark_interval = watermark_interval
325330 . unwrap_or ( DEFAULT_WATERMARK_INTERVAL )
326331 . max ( 1 ) ;
@@ -348,6 +353,7 @@ impl SubscriptionService {
348353 shards : shard_senders,
349354 next_shard : 0 ,
350355 counters,
356+ max_subscribers,
351357 indexed_checkpoint,
352358 metrics,
353359 }
@@ -510,10 +516,10 @@ impl SubscriptionService {
510516 // can have at one time. `counters.total` is incremented here at
511517 // admission and decremented by the shards on departure/clear, so it
512518 // counts live + in-flight subscribers across every shard.
513- if self . counters . total . load ( Ordering :: Relaxed ) >= MAX_SUBSCRIBERS {
519+ if self . counters . total . load ( Ordering :: Relaxed ) >= self . max_subscribers {
514520 trace ! (
515521 "failed to register new subscriber: hit maximum number of subscribers {}" ,
516- MAX_SUBSCRIBERS
522+ self . max_subscribers
517523 ) ;
518524 // Dropping the oneshot makes `register_subscription` return
519525 // `None` -> `Status::unavailable`.
@@ -607,6 +613,7 @@ mod tests {
607613 shards : shard_senders,
608614 next_shard : 0 ,
609615 counters,
616+ max_subscribers : DEFAULT_MAX_SUBSCRIBERS ,
610617 indexed_checkpoint,
611618 metrics,
612619 } ;
@@ -902,26 +909,23 @@ mod tests {
902909 }
903910
904911 #[ tokio:: test]
905- async fn cap_is_enforced_globally_across_shards ( ) {
912+ async fn configured_cap_is_enforced_globally_across_shards ( ) {
906913 let ( mut service, mut shards) = test_service ( 2 ) ;
907- let mut receivers = Vec :: with_capacity ( MAX_SUBSCRIBERS ) ;
908- for i in 0 ..MAX_SUBSCRIBERS {
909- // Keep each 64-slot shard mailbox from filling: the dispatcher's
910- // bounded send would otherwise block with no spawned shard task.
911- if i % 32 == 0 {
912- drain ( & mut shards) ;
913- }
914+ let max_subscribers = 3 ;
915+ service. max_subscribers = max_subscribers;
916+ let mut receivers = Vec :: with_capacity ( max_subscribers) ;
917+ for _ in 0 ..max_subscribers {
914918 receivers. push ( register ( & mut service, unfiltered ( ) ) . await . unwrap ( ) ) ;
915919 }
916920 drain ( & mut shards) ;
917921 assert_eq ! (
918922 service. counters. total. load( Ordering :: Relaxed ) ,
919- MAX_SUBSCRIBERS
923+ max_subscribers
920924 ) ;
921925 // The gauge mirrors the admission count for observability.
922926 assert_eq ! (
923927 service. metrics. inflight_subscribers. get( ) ,
924- MAX_SUBSCRIBERS as i64
928+ max_subscribers as i64
925929 ) ;
926930 assert ! ( !shards[ 0 ] . matcher. is_empty( ) ) ;
927931 assert ! ( !shards[ 1 ] . matcher. is_empty( ) ) ;
0 commit comments