Skip to main content

meta_srv/
handler.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::cmp::Ordering;
16use std::collections::{BTreeMap, HashMap, HashSet};
17use std::fmt::{Debug, Display};
18use std::ops::Bound;
19use std::sync::{Arc, Mutex};
20use std::time::{Duration, Instant};
21
22use api::v1::meta::mailbox_message::Payload;
23use api::v1::meta::{
24    HeartbeatConfig, HeartbeatRequest, HeartbeatResponse, MailboxMessage, PROTOCOL_VERSION,
25    RegionLease, ResponseHeader, Role,
26};
27use check_leader_handler::CheckLeaderHandler;
28use collect_cluster_info_handler::{
29    CollectDatanodeClusterInfoHandler, CollectFlownodeClusterInfoHandler,
30    CollectFrontendClusterInfoHandler,
31};
32use collect_leader_region_handler::CollectLeaderRegionHandler;
33use collect_stats_handler::CollectStatsHandler;
34use common_base::Plugins;
35use common_meta::datanode::Stat;
36use common_meta::instruction::InstructionReply;
37use common_meta::sequence::Sequence;
38use common_telemetry::{debug, info, warn};
39use dashmap::DashMap;
40use extract_stat_handler::ExtractStatHandler;
41use failure_handler::RegionFailureHandler;
42use filter_inactive_region_stats::FilterInactiveRegionStatsHandler;
43use futures::future::join_all;
44use keep_lease_handler::{DatanodeKeepLeaseHandler, FlownodeKeepLeaseHandler};
45use mailbox_handler::MailboxHandler;
46use on_leader_start_handler::OnLeaderStartHandler;
47use publish_heartbeat_handler::PublishHeartbeatHandler;
48use region_lease_handler::RegionLeaseHandler;
49use remap_flow_peer_handler::RemapFlowPeerHandler;
50use response_header_handler::ResponseHeaderHandler;
51use snafu::{OptionExt, ResultExt};
52use store_api::storage::RegionId;
53use tokio::sync::mpsc::Sender;
54use tokio::sync::{Notify, RwLock, oneshot, watch};
55
56use crate::error::{self, DeserializeFromJsonSnafu, Result, UnexpectedInstructionReplySnafu};
57use crate::handler::collect_topic_stats_handler::CollectTopicStatsHandler;
58use crate::handler::flow_state_handler::FlowStateHandler;
59use crate::handler::persist_stats_handler::PersistStatsHandler;
60use crate::metasrv::Context;
61use crate::metrics::{METRIC_META_HANDLER_EXECUTE, METRIC_META_HEARTBEAT_CONNECTION_NUM};
62use crate::pubsub::PublisherRef;
63use crate::service::mailbox::{
64    BroadcastChannel, Channel, Mailbox, MailboxReceiver, MailboxRef, MessageId,
65};
66
67pub mod check_leader_handler;
68pub mod collect_cluster_info_handler;
69pub mod collect_leader_region_handler;
70pub mod collect_stats_handler;
71pub mod collect_topic_stats_handler;
72pub mod extract_stat_handler;
73pub mod failure_handler;
74pub mod filter_inactive_region_stats;
75pub mod flow_state_handler;
76pub mod keep_lease_handler;
77pub mod mailbox_handler;
78pub mod on_leader_start_handler;
79pub mod persist_stats_handler;
80pub mod publish_heartbeat_handler;
81pub mod region_lease_handler;
82pub mod remap_flow_peer_handler;
83pub mod response_header_handler;
84mod utils;
85
86#[cfg(test)]
87pub mod test_utils;
88
89#[async_trait::async_trait]
90pub trait HeartbeatHandler: Send + Sync {
91    fn is_acceptable(&self, role: Role) -> bool;
92
93    fn name(&self) -> &'static str {
94        let type_name = std::any::type_name::<Self>();
95        // short name
96        type_name.split("::").last().unwrap_or(type_name)
97    }
98
99    async fn handle(
100        &self,
101        req: &HeartbeatRequest,
102        ctx: &mut Context,
103        acc: &mut HeartbeatAccumulator,
104    ) -> Result<HandleControl>;
105}
106
107/// HandleControl
108///
109/// Controls process of handling heartbeat request.
110#[derive(PartialEq, Debug)]
111pub enum HandleControl {
112    Continue,
113    Done,
114}
115
116#[derive(Debug, Default)]
117pub struct HeartbeatAccumulator {
118    pub header: Option<ResponseHeader>,
119    mailbox_message: Option<MailboxMessage>,
120    pub stat: Option<Stat>,
121    pub inactive_region_ids: HashSet<RegionId>,
122    pub region_lease: Option<RegionLease>,
123    /// Generic heartbeat response extensions accumulated by handlers.
124    pub extensions: HashMap<String, Vec<u8>>,
125}
126
127impl HeartbeatAccumulator {
128    pub(crate) fn take_mailbox_message(&mut self) -> Option<MailboxMessage> {
129        self.mailbox_message.take()
130    }
131
132    pub fn set_mailbox_message(&mut self, message: MailboxMessage) {
133        let _ = self.mailbox_message.insert(message);
134    }
135}
136
137#[derive(Copy, Clone)]
138pub struct PusherId {
139    pub role: Role,
140    pub id: u64,
141}
142
143impl PartialEq for PusherId {
144    fn eq(&self, other: &Self) -> bool {
145        self.role as i32 == other.role as i32 && self.id == other.id
146    }
147}
148
149impl Eq for PusherId {}
150
151impl PartialOrd for PusherId {
152    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
153        Some(self.cmp(other))
154    }
155}
156
157impl Ord for PusherId {
158    fn cmp(&self, other: &Self) -> Ordering {
159        (self.role as i32, self.id).cmp(&(other.role as i32, other.id))
160    }
161}
162
163impl Debug for PusherId {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        write!(f, "{:?}-{}", self.role, self.id)
166    }
167}
168
169impl Display for PusherId {
170    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171        write!(f, "{:?}-{}", self.role, self.id)
172    }
173}
174
175impl PusherId {
176    pub fn new(role: Role, id: u64) -> Self {
177        Self { role, id }
178    }
179
180    fn role_range(role: Role) -> (Bound<Self>, Bound<Self>) {
181        (
182            Bound::Included(Self::new(role, u64::MIN)),
183            Bound::Included(Self::new(role, u64::MAX)),
184        )
185    }
186}
187
188/// The receiver of the deregister signal.
189pub type DeregisterSignalReceiver = watch::Receiver<bool>;
190
191/// The pusher of the heartbeat response.
192pub struct Pusher {
193    sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>,
194    // The sender of the deregister signal.
195    // default is false, means the pusher is not deregistered.
196    // when the pusher is deregistered, the sender will be notified.
197    deregister_signal_sender: watch::Sender<bool>,
198    deregister_signal_receiver: DeregisterSignalReceiver,
199
200    res_header: ResponseHeader,
201}
202
203impl Drop for Pusher {
204    fn drop(&mut self) {
205        // Ignore the error here.
206        // if all the receivers have been dropped, means no body cares the deregister signal.
207        let _ = self.deregister_signal_sender.send(true);
208    }
209}
210
211impl Pusher {
212    pub fn new(sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>) -> Self {
213        let res_header = ResponseHeader {
214            protocol_version: PROTOCOL_VERSION,
215            ..Default::default()
216        };
217        let (deregister_signal_sender, deregister_signal_receiver) = watch::channel(false);
218        Self {
219            sender,
220            deregister_signal_sender,
221            deregister_signal_receiver,
222            res_header,
223        }
224    }
225
226    #[inline]
227    pub fn header(&self) -> ResponseHeader {
228        self.res_header.clone()
229    }
230}
231
232/// An owned snapshot of the [`Pusher`] fields the push paths need, so a caller can drop
233/// the [`Pushers`] read guard before awaiting the send. It must not hold a [`Pusher`]:
234/// dropping one fires the deregister signal, which reads as a closed channel.
235struct PusherHandle {
236    sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>,
237    res_header: ResponseHeader,
238    deregister_signal_receiver: DeregisterSignalReceiver,
239}
240
241impl PusherHandle {
242    /// Snapshots `pusher`, which callers read under the [`Pushers`] guard.
243    fn from_pusher(pusher: &Pusher) -> Self {
244        Self {
245            sender: pusher.sender.clone(),
246            res_header: pusher.header(),
247            deregister_signal_receiver: pusher.deregister_signal_receiver.clone(),
248        }
249    }
250
251    /// Sends one mailbox message, consuming the handle.
252    async fn push(self, mailbox_message: MailboxMessage) -> Result<()> {
253        self.sender
254            .send(Ok(HeartbeatResponse {
255                header: Some(self.res_header),
256                mailbox_message: Some(mailbox_message),
257                ..Default::default()
258            }))
259            .await
260            .map_err(|e| {
261                error::PushMessageSnafu {
262                    err_msg: e.to_string(),
263                }
264                .build()
265            })
266    }
267
268    #[inline]
269    fn deregister_signal_receiver(&self) -> DeregisterSignalReceiver {
270        self.deregister_signal_receiver.clone()
271    }
272}
273
274/// The group of heartbeat pushers.
275#[derive(Clone, Default)]
276pub struct Pushers(Arc<RwLock<BTreeMap<PusherId, Pusher>>>);
277
278impl Pushers {
279    async fn push(
280        &self,
281        pusher_id: PusherId,
282        mailbox_message: MailboxMessage,
283    ) -> Result<DeregisterSignalReceiver> {
284        // Releases the guard before the send below, which parks while the target's
285        // channel is full. `PusherNotFound` is still reported from inside the guard.
286        let handle = {
287            let pushers = self.0.read().await;
288            let pusher = pushers
289                .get(&pusher_id)
290                .with_context(|| error::PusherNotFoundSnafu {
291                    pusher_id: pusher_id.to_string(),
292                })?;
293            PusherHandle::from_pusher(pusher)
294        };
295
296        let deregister_signal_receiver = handle.deregister_signal_receiver();
297        handle.push(mailbox_message).await?;
298
299        Ok(deregister_signal_receiver)
300    }
301
302    async fn broadcast(&self, role: Role, mailbox_message: &MailboxMessage) -> Result<()> {
303        // Collects owned handles, releasing the guard before the sends below. Collecting
304        // `&Pusher` would hold it for the whole `join_all`.
305        let targets = {
306            let pushers = self.0.read().await;
307            pushers
308                .range(PusherId::role_range(role))
309                .map(|(_, pusher)| PusherHandle::from_pusher(pusher))
310                .collect::<Vec<_>>()
311        };
312
313        let mut results = Vec::with_capacity(targets.len());
314        for handle in targets {
315            let mut mailbox_message = mailbox_message.clone();
316            mailbox_message.id = 0; // one-way message
317
318            results.push(handle.push(mailbox_message));
319        }
320
321        // Checks the error out of the loop.
322        let _ = join_all(results)
323            .await
324            .into_iter()
325            .collect::<Result<Vec<_>>>()?;
326
327        Ok(())
328    }
329
330    pub(crate) async fn insert(&self, pusher_id: PusherId, pusher: Pusher) -> Option<Pusher> {
331        self.0.write().await.insert(pusher_id, pusher)
332    }
333
334    async fn remove(&self, pusher_id: PusherId) -> Option<Pusher> {
335        self.0.write().await.remove(&pusher_id)
336    }
337}
338
339#[derive(Clone)]
340pub struct NameCachedHandler {
341    name: &'static str,
342    handler: Arc<dyn HeartbeatHandler>,
343}
344
345impl NameCachedHandler {
346    fn new(handler: impl HeartbeatHandler + 'static) -> Self {
347        let name = handler.name();
348        let handler = Arc::new(handler);
349        Self { name, handler }
350    }
351}
352
353pub type HeartbeatHandlerGroupRef = Arc<HeartbeatHandlerGroup>;
354
355/// The group of heartbeat handlers.
356#[derive(Default, Clone)]
357pub struct HeartbeatHandlerGroup {
358    handlers: Vec<NameCachedHandler>,
359    pushers: Pushers,
360}
361
362impl HeartbeatHandlerGroup {
363    /// Registers the heartbeat response [`Pusher`] with the given key to the group.
364    pub async fn register_pusher(&self, pusher_id: PusherId, pusher: Pusher) {
365        METRIC_META_HEARTBEAT_CONNECTION_NUM.inc();
366        info!("Pusher register: {}", pusher_id);
367        let _ = self.pushers.insert(pusher_id, pusher).await;
368    }
369
370    /// Deregisters the heartbeat response [`Pusher`] with the given key from the group.
371    pub async fn deregister_push(&self, pusher_id: PusherId) {
372        if self.pushers.remove(pusher_id).await.is_some() {
373            info!("Pusher unregister: {}", pusher_id);
374            METRIC_META_HEARTBEAT_CONNECTION_NUM.dec();
375        }
376    }
377
378    #[cfg(test)]
379    /// Returns whether the group contains the heartbeat response [`Pusher`] with the given key.
380    pub async fn contains_pusher(&self, pusher_id: &PusherId) -> bool {
381        let pushers = self.pushers.0.read().await;
382        pushers.contains_key(pusher_id)
383    }
384
385    /// Returns the [`Pushers`] of the group.
386    pub fn pushers(&self) -> Pushers {
387        self.pushers.clone()
388    }
389
390    /// Handles the heartbeat request.
391    pub async fn handle(
392        &self,
393        req: HeartbeatRequest,
394        mut ctx: Context,
395    ) -> Result<HeartbeatResponse> {
396        let mut acc = HeartbeatAccumulator::default();
397        let role = req
398            .header
399            .as_ref()
400            .and_then(|h| Role::try_from(h.role).ok())
401            .context(error::InvalidArgumentsSnafu {
402                err_msg: format!("invalid role: {:?}", req.header),
403            })?;
404
405        let is_handshake = ctx.is_handshake;
406
407        for NameCachedHandler { name, handler } in self.handlers.iter() {
408            if !handler.is_acceptable(role) {
409                continue;
410            }
411
412            let _timer = METRIC_META_HANDLER_EXECUTE
413                .with_label_values(&[*name])
414                .start_timer();
415
416            if handler.handle(&req, &mut ctx, &mut acc).await? == HandleControl::Done {
417                break;
418            }
419        }
420        let header = std::mem::take(&mut acc.header);
421        let mailbox_message = acc.take_mailbox_message();
422
423        // Populate heartbeat_config during handshake
424        let heartbeat_config = if is_handshake {
425            let mut config: HeartbeatConfig = ctx.heartbeat_options_for(role).into();
426            config.gc_enabled = ctx.gc_enabled;
427
428            info!(
429                "Handshake with {:?} node, sending config: {:?}",
430                role, config
431            );
432
433            Some(config)
434        } else {
435            None
436        };
437
438        let res = HeartbeatResponse {
439            header,
440            region_lease: acc.region_lease,
441            mailbox_message,
442            heartbeat_config,
443            extensions: std::mem::take(&mut acc.extensions),
444        };
445        Ok(res)
446    }
447}
448
449pub struct HeartbeatMailbox {
450    pushers: Pushers,
451    sequence: Sequence,
452    senders: DashMap<MessageId, oneshot::Sender<Result<MailboxMessage>>>,
453    timeouts: DashMap<MessageId, Instant>,
454    timeout_notify: Notify,
455}
456
457impl HeartbeatMailbox {
458    pub fn json_reply(msg: &MailboxMessage) -> Result<InstructionReply> {
459        let Payload::Json(payload) =
460            msg.payload
461                .as_ref()
462                .with_context(|| UnexpectedInstructionReplySnafu {
463                    mailbox_message: msg.to_string(),
464                    reason: "empty JSON payload".to_string(),
465                })?;
466        serde_json::from_str(payload).context(DeserializeFromJsonSnafu {
467            input_len: payload.len(),
468        })
469    }
470
471    /// Parses the [Instruction] from [MailboxMessage].
472    #[cfg(test)]
473    pub(crate) fn json_instruction(
474        msg: &MailboxMessage,
475    ) -> Result<common_meta::instruction::Instruction> {
476        let Payload::Json(payload) =
477            msg.payload
478                .as_ref()
479                .with_context(|| UnexpectedInstructionReplySnafu {
480                    mailbox_message: msg.to_string(),
481                    reason: "empty JSON payload".to_string(),
482                })?;
483        serde_json::from_str(payload).context(DeserializeFromJsonSnafu {
484            input_len: payload.len(),
485        })
486    }
487
488    pub fn create(pushers: Pushers, sequence: Sequence) -> MailboxRef {
489        let mailbox = Arc::new(Self::new(pushers, sequence));
490
491        let timeout_checker = mailbox.clone();
492        let _handle = common_runtime::spawn_global(async move {
493            timeout_checker.check_timeout_bg(10).await;
494        });
495
496        mailbox
497    }
498
499    fn new(pushers: Pushers, sequence: Sequence) -> Self {
500        Self {
501            pushers,
502            sequence,
503            senders: DashMap::default(),
504            timeouts: DashMap::default(),
505            timeout_notify: Notify::new(),
506        }
507    }
508
509    async fn check_timeout_bg(&self, interval_millis: u64) {
510        let mut interval = tokio::time::interval(Duration::from_millis(interval_millis));
511
512        loop {
513            let _ = interval.tick().await;
514
515            if self.timeouts.is_empty() {
516                self.timeout_notify.notified().await;
517            }
518
519            let now = Instant::now();
520            let timeout_ids = self
521                .timeouts
522                .iter()
523                .filter_map(|entry| {
524                    let (id, deadline) = entry.pair();
525                    if deadline < &now { Some(*id) } else { None }
526                })
527                .collect::<Vec<_>>();
528
529            for id in timeout_ids {
530                let _ = self
531                    .on_recv(id, Err(error::MailboxTimeoutSnafu { id }.build()))
532                    .await;
533            }
534        }
535    }
536
537    #[inline]
538    async fn next_message_id(&self) -> Result<u64> {
539        // In this implementation, we pre-occupy the message_id of 0,
540        // and we use `message_id = 0` to mark a Message as a one-way call.
541        loop {
542            let next = self
543                .sequence
544                .next()
545                .await
546                .context(error::NextSequenceSnafu)?;
547            if next > 0 {
548                return Ok(next);
549            }
550        }
551    }
552}
553
554#[async_trait::async_trait]
555impl Mailbox for HeartbeatMailbox {
556    async fn send(
557        &self,
558        ch: &Channel,
559        mut msg: MailboxMessage,
560        timeout: Duration,
561    ) -> Result<MailboxReceiver> {
562        let message_id = self.next_message_id().await?;
563        msg.id = message_id;
564
565        let pusher_id = ch.pusher_id();
566        let payload_len = msg
567            .payload
568            .as_ref()
569            .map(|Payload::Json(payload)| payload.len())
570            .unwrap_or_default();
571        debug!(message_id, payload_len, %pusher_id, "Sending mailbox message");
572
573        let (tx, rx) = oneshot::channel();
574        let _ = self.senders.insert(message_id, tx);
575        let deadline = Instant::now() + timeout;
576        self.timeouts.insert(message_id, deadline);
577        self.timeout_notify.notify_one();
578        let deregister_signal_receiver = self.pushers.push(pusher_id, msg).await?;
579
580        Ok(MailboxReceiver::new(
581            message_id,
582            rx,
583            deregister_signal_receiver,
584            *ch,
585        ))
586    }
587
588    async fn send_oneway(&self, ch: &Channel, mut msg: MailboxMessage) -> Result<()> {
589        let message_id = 0; // one-way message, same as `broadcast`
590        msg.id = message_id;
591
592        let pusher_id = ch.pusher_id();
593        let payload_len = msg
594            .payload
595            .as_ref()
596            .map(|Payload::Json(payload)| payload.len())
597            .unwrap_or_default();
598        debug!(message_id, payload_len, %pusher_id, "Sending one-way mailbox message");
599
600        self.pushers.push(pusher_id, msg).await?;
601
602        Ok(())
603    }
604
605    async fn broadcast(&self, ch: &BroadcastChannel, msg: &MailboxMessage) -> Result<()> {
606        self.pushers.broadcast(ch.role(), msg).await
607    }
608
609    async fn on_recv(&self, id: MessageId, maybe_msg: Result<MailboxMessage>) -> Result<()> {
610        let payload_len = maybe_msg
611            .as_ref()
612            .ok()
613            .and_then(|msg| msg.payload.as_ref())
614            .map(|Payload::Json(payload)| payload.len())
615            .unwrap_or_default();
616        debug!(
617            message_id = id,
618            payload_len,
619            success = maybe_msg.is_ok(),
620            "Received mailbox message"
621        );
622
623        let _ = self.timeouts.remove(&id);
624
625        if let Some((_, tx)) = self.senders.remove(&id) {
626            tx.send(maybe_msg)
627                .map_err(|_| error::MailboxClosedSnafu { id }.build())?;
628        } else if let Ok(finally_msg) = maybe_msg {
629            let payload_len = finally_msg
630                .payload
631                .as_ref()
632                .map(|Payload::Json(payload)| payload.len())
633                .unwrap_or_default();
634            warn!(
635                message_id = id,
636                payload_len, "The mailbox response arrived too late"
637            );
638        }
639
640        Ok(())
641    }
642}
643
644/// The builder to build the group of heartbeat handlers.
645pub struct HeartbeatHandlerGroupBuilder {
646    /// The handler to handle region failure.
647    region_failure_handler: Option<RegionFailureHandler>,
648
649    /// The handler to handle region lease.
650    region_lease_handler: Option<RegionLeaseHandler>,
651
652    /// The factor that determines how often statistics should be flushed,
653    /// based on the number of received heartbeats. When the number of heartbeats
654    /// reaches this factor, a flush operation is triggered.
655    flush_stats_factor: Option<usize>,
656    /// A simple handler for flow internal state report
657    flow_state_handler: Option<FlowStateHandler>,
658
659    /// The handler to persist stats.
660    persist_stats_handler: Option<PersistStatsHandler>,
661
662    /// The plugins.
663    plugins: Option<Plugins>,
664
665    /// The heartbeat response pushers.
666    pushers: Pushers,
667
668    /// The group of heartbeat handlers.
669    handlers: Vec<NameCachedHandler>,
670}
671
672impl HeartbeatHandlerGroupBuilder {
673    pub fn new(pushers: Pushers) -> Self {
674        Self {
675            region_failure_handler: None,
676            region_lease_handler: None,
677            flush_stats_factor: None,
678            flow_state_handler: None,
679            persist_stats_handler: None,
680            plugins: None,
681            pushers,
682            handlers: vec![],
683        }
684    }
685
686    pub fn with_flow_state_handler(mut self, handler: Option<FlowStateHandler>) -> Self {
687        self.flow_state_handler = handler;
688        self
689    }
690
691    pub fn with_region_lease_handler(mut self, handler: Option<RegionLeaseHandler>) -> Self {
692        self.region_lease_handler = handler;
693        self
694    }
695
696    /// Sets the [`RegionFailureHandler`].
697    pub fn with_region_failure_handler(mut self, handler: Option<RegionFailureHandler>) -> Self {
698        self.region_failure_handler = handler;
699        self
700    }
701
702    /// Sets the flush stats factor.
703    pub fn with_flush_stats_factor(mut self, flush_stats_factor: Option<usize>) -> Self {
704        self.flush_stats_factor = flush_stats_factor;
705        self
706    }
707
708    pub fn with_persist_stats_handler(mut self, handler: Option<PersistStatsHandler>) -> Self {
709        self.persist_stats_handler = handler;
710        self
711    }
712
713    /// Sets the [`Plugins`].
714    pub fn with_plugins(mut self, plugins: Option<Plugins>) -> Self {
715        self.plugins = plugins;
716        self
717    }
718
719    /// Adds the default handlers.
720    pub fn add_default_handlers(mut self) -> Self {
721        // Extract the `PublishHeartbeatHandler` from the plugins.
722        let publish_heartbeat_handler = if let Some(plugins) = self.plugins.as_ref() {
723            plugins
724                .get::<PublisherRef>()
725                .map(|publish| PublishHeartbeatHandler::new(publish.clone()))
726        } else {
727            None
728        };
729
730        self.add_handler_last(ResponseHeaderHandler);
731        // `KeepLeaseHandler` should preferably be in front of `CheckLeaderHandler`,
732        // because even if the current meta-server node is no longer the leader it can
733        // still help the datanode to keep lease.
734        self.add_handler_last(DatanodeKeepLeaseHandler);
735        self.add_handler_last(FlownodeKeepLeaseHandler);
736        self.add_handler_last(CheckLeaderHandler);
737        self.add_handler_last(OnLeaderStartHandler);
738        self.add_handler_last(ExtractStatHandler);
739        self.add_handler_last(CollectDatanodeClusterInfoHandler);
740        self.add_handler_last(CollectFrontendClusterInfoHandler);
741        self.add_handler_last(CollectFlownodeClusterInfoHandler);
742        self.add_handler_last(MailboxHandler);
743        if let Some(region_lease_handler) = self.region_lease_handler.take() {
744            self.add_handler_last(region_lease_handler);
745        }
746        self.add_handler_last(FilterInactiveRegionStatsHandler);
747        if let Some(region_failure_handler) = self.region_failure_handler.take() {
748            self.add_handler_last(region_failure_handler);
749        }
750        if let Some(publish_heartbeat_handler) = publish_heartbeat_handler {
751            self.add_handler_last(publish_heartbeat_handler);
752        }
753        self.add_handler_last(CollectLeaderRegionHandler);
754        self.add_handler_last(CollectTopicStatsHandler);
755        // Persist stats handler should be in front of collect stats handler.
756        // Because collect stats handler will consume the stats from the accumulator.
757        if let Some(persist_stats_handler) = self.persist_stats_handler.take() {
758            self.add_handler_last(persist_stats_handler);
759        }
760        self.add_handler_last(CollectStatsHandler::new(self.flush_stats_factor));
761        self.add_handler_last(RemapFlowPeerHandler::default());
762
763        if let Some(flow_state_handler) = self.flow_state_handler.take() {
764            self.add_handler_last(flow_state_handler);
765        }
766
767        self
768    }
769
770    /// Builds the group of heartbeat handlers.
771    ///
772    /// Applies the customizer if it exists.
773    pub fn build(mut self) -> Result<HeartbeatHandlerGroup> {
774        if let Some(customizer) = self
775            .plugins
776            .as_ref()
777            .and_then(|plugins| plugins.get::<HeartbeatHandlerGroupBuilderCustomizerRef>())
778        {
779            debug!("Customizing the heartbeat handler group builder");
780            customizer.customize(&mut self)?;
781        }
782
783        Ok(HeartbeatHandlerGroup {
784            handlers: self.handlers,
785            pushers: self.pushers,
786        })
787    }
788
789    fn add_handler_after_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
790        if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
791            self.handlers.insert(pos + 1, handler);
792            return Ok(());
793        }
794
795        error::HandlerNotFoundSnafu { name: target }.fail()
796    }
797
798    /// Adds the handler after the specified handler.
799    pub fn add_handler_after(
800        &mut self,
801        target: &'static str,
802        handler: impl HeartbeatHandler + 'static,
803    ) -> Result<()> {
804        self.add_handler_after_inner(target, NameCachedHandler::new(handler))
805    }
806
807    fn add_handler_before_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
808        if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
809            self.handlers.insert(pos, handler);
810            return Ok(());
811        }
812
813        error::HandlerNotFoundSnafu { name: target }.fail()
814    }
815
816    /// Adds the handler before the specified handler.
817    pub fn add_handler_before(
818        &mut self,
819        target: &'static str,
820        handler: impl HeartbeatHandler + 'static,
821    ) -> Result<()> {
822        self.add_handler_before_inner(target, NameCachedHandler::new(handler))
823    }
824
825    fn replace_handler_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
826        if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
827            self.handlers[pos] = handler;
828            return Ok(());
829        }
830
831        error::HandlerNotFoundSnafu { name: target }.fail()
832    }
833
834    /// Replaces the handler with the specified name.
835    pub fn replace_handler(
836        &mut self,
837        target: &'static str,
838        handler: impl HeartbeatHandler + 'static,
839    ) -> Result<()> {
840        self.replace_handler_inner(target, NameCachedHandler::new(handler))
841    }
842
843    fn add_handler_last_inner(&mut self, handler: NameCachedHandler) {
844        self.handlers.push(handler);
845    }
846
847    fn add_handler_last(&mut self, handler: impl HeartbeatHandler + 'static) {
848        self.add_handler_last_inner(NameCachedHandler::new(handler));
849    }
850}
851
852pub type HeartbeatHandlerGroupBuilderCustomizerRef =
853    Arc<dyn HeartbeatHandlerGroupBuilderCustomizer>;
854
855pub enum CustomizeHeartbeatGroupAction {
856    AddHandlerAfter {
857        target: String,
858        handler: NameCachedHandler,
859    },
860    AddHandlerBefore {
861        target: String,
862        handler: NameCachedHandler,
863    },
864    ReplaceHandler {
865        target: String,
866        handler: NameCachedHandler,
867    },
868    AddHandlerLast {
869        handler: NameCachedHandler,
870    },
871}
872
873impl CustomizeHeartbeatGroupAction {
874    pub fn new_add_handler_after(
875        target: &'static str,
876        handler: impl HeartbeatHandler + 'static,
877    ) -> Self {
878        Self::AddHandlerAfter {
879            target: target.to_string(),
880            handler: NameCachedHandler::new(handler),
881        }
882    }
883
884    pub fn new_add_handler_before(
885        target: &'static str,
886        handler: impl HeartbeatHandler + 'static,
887    ) -> Self {
888        Self::AddHandlerBefore {
889            target: target.to_string(),
890            handler: NameCachedHandler::new(handler),
891        }
892    }
893
894    pub fn new_replace_handler(
895        target: &'static str,
896        handler: impl HeartbeatHandler + 'static,
897    ) -> Self {
898        Self::ReplaceHandler {
899            target: target.to_string(),
900            handler: NameCachedHandler::new(handler),
901        }
902    }
903
904    pub fn new_add_handler_last(handler: impl HeartbeatHandler + 'static) -> Self {
905        Self::AddHandlerLast {
906            handler: NameCachedHandler::new(handler),
907        }
908    }
909}
910
911/// The customizer of the [`HeartbeatHandlerGroupBuilder`].
912pub trait HeartbeatHandlerGroupBuilderCustomizer: Send + Sync {
913    fn customize(&self, builder: &mut HeartbeatHandlerGroupBuilder) -> Result<()>;
914
915    fn add_action(&self, action: CustomizeHeartbeatGroupAction);
916}
917
918#[derive(Default)]
919pub struct DefaultHeartbeatHandlerGroupBuilderCustomizer {
920    actions: Mutex<Vec<CustomizeHeartbeatGroupAction>>,
921}
922
923impl HeartbeatHandlerGroupBuilderCustomizer for DefaultHeartbeatHandlerGroupBuilderCustomizer {
924    fn customize(&self, builder: &mut HeartbeatHandlerGroupBuilder) -> Result<()> {
925        info!("Customizing the heartbeat handler group builder");
926        let mut actions = self.actions.lock().unwrap();
927        for action in actions.drain(..) {
928            match action {
929                CustomizeHeartbeatGroupAction::AddHandlerAfter { target, handler } => {
930                    builder.add_handler_after_inner(&target, handler)?;
931                }
932                CustomizeHeartbeatGroupAction::AddHandlerBefore { target, handler } => {
933                    builder.add_handler_before_inner(&target, handler)?;
934                }
935                CustomizeHeartbeatGroupAction::ReplaceHandler { target, handler } => {
936                    builder.replace_handler_inner(&target, handler)?;
937                }
938                CustomizeHeartbeatGroupAction::AddHandlerLast { handler } => {
939                    builder.add_handler_last_inner(handler);
940                }
941            }
942        }
943        Ok(())
944    }
945
946    fn add_action(&self, action: CustomizeHeartbeatGroupAction) {
947        self.actions.lock().unwrap().push(action);
948    }
949}
950
951#[cfg(test)]
952mod tests {
953
954    use std::assert_matches;
955    use std::collections::BTreeMap;
956    use std::sync::Arc;
957    use std::time::Duration;
958
959    use api::v1::meta::{HeartbeatRequest, HeartbeatResponse, MailboxMessage, RequestHeader, Role};
960    use common_meta::kv_backend::memory::MemoryKvBackend;
961    use common_meta::sequence::SequenceBuilder;
962    use futures::future::poll_immediate;
963    use tokio::sync::mpsc;
964
965    use super::{
966        HandleControl, HeartbeatAccumulator, HeartbeatHandler, HeartbeatHandlerGroupBuilder,
967        PusherHandle, PusherId, Pushers,
968    };
969    use crate::error;
970    use crate::handler::collect_stats_handler::CollectStatsHandler;
971    use crate::handler::response_header_handler::ResponseHeaderHandler;
972    use crate::handler::test_utils::TestEnv;
973    use crate::handler::{HeartbeatHandlerGroup, HeartbeatMailbox, Pusher};
974    use crate::metasrv::Context;
975    use crate::service::mailbox::{Channel, MailboxReceiver, MailboxRef};
976
977    #[tokio::test]
978    async fn test_mailbox() {
979        let (mailbox, receiver) = push_msg_via_mailbox().await;
980        let id = receiver.message_id();
981
982        let resp_msg = MailboxMessage {
983            id,
984            subject: "resp-test".to_string(),
985            timestamp_millis: 456,
986            ..Default::default()
987        };
988
989        mailbox.on_recv(id, Ok(resp_msg)).await.unwrap();
990
991        let recv_msg = receiver.await.unwrap();
992        assert_eq!(recv_msg.id, id);
993        assert_eq!(recv_msg.timestamp_millis, 456);
994        assert_eq!(recv_msg.subject, "resp-test".to_string());
995    }
996
997    #[tokio::test]
998    async fn test_mailbox_timeout() {
999        let (_, receiver) = push_msg_via_mailbox().await;
1000        let res = receiver.await;
1001        assert!(res.is_err());
1002    }
1003
1004    async fn push_msg_via_mailbox() -> (MailboxRef, MailboxReceiver) {
1005        let datanode_id = 12;
1006        let (pusher_tx, mut pusher_rx) = mpsc::channel(16);
1007        let pusher_id = PusherId::new(Role::Datanode, datanode_id);
1008        let pusher: Pusher = Pusher::new(pusher_tx);
1009        let handler_group = HeartbeatHandlerGroup::default();
1010        handler_group.register_pusher(pusher_id, pusher).await;
1011
1012        let kv_backend = Arc::new(MemoryKvBackend::new());
1013        let seq = SequenceBuilder::new("test_seq", kv_backend).build();
1014        let mailbox = HeartbeatMailbox::create(handler_group.pushers(), seq);
1015
1016        let msg = MailboxMessage {
1017            id: 0,
1018            subject: "req-test".to_string(),
1019            timestamp_millis: 123,
1020            ..Default::default()
1021        };
1022        let ch = Channel::Datanode(datanode_id);
1023
1024        let receiver = mailbox
1025            .send(&ch, msg, Duration::from_secs(1))
1026            .await
1027            .unwrap();
1028
1029        let recv_obj = pusher_rx.recv().await.unwrap().unwrap();
1030        let message = recv_obj.mailbox_message.unwrap();
1031        assert_eq!(message.timestamp_millis, 123);
1032        assert_eq!(message.subject, "req-test".to_string());
1033
1034        (mailbox, receiver)
1035    }
1036
1037    #[test]
1038    fn test_pusher_id_role_range() {
1039        let mut pushers = BTreeMap::new();
1040        pushers.insert(PusherId::new(Role::Datanode, u64::MAX), "datanode");
1041        pushers.insert(PusherId::new(Role::Frontend, u64::MIN), "frontend-min");
1042        pushers.insert(PusherId::new(Role::Frontend, u64::MAX), "frontend-max");
1043        pushers.insert(PusherId::new(Role::Flownode, u64::MIN), "flownode");
1044
1045        let frontend_pushers = pushers
1046            .range(PusherId::role_range(Role::Frontend))
1047            .map(|(_, value)| *value)
1048            .collect::<Vec<_>>();
1049
1050        assert_eq!(frontend_pushers, vec!["frontend-min", "frontend-max"]);
1051    }
1052
1053    #[tokio::test]
1054    async fn test_pushers_broadcast_by_role() {
1055        let pushers = Pushers::default();
1056        let (datanode_tx, mut datanode_rx) = mpsc::channel(1);
1057        let (frontend_tx, mut frontend_rx) = mpsc::channel(1);
1058        let (flownode_tx, mut flownode_rx) = mpsc::channel(1);
1059
1060        pushers
1061            .insert(
1062                PusherId::new(Role::Datanode, u64::MAX),
1063                Pusher::new(datanode_tx),
1064            )
1065            .await;
1066        pushers
1067            .insert(PusherId::new(Role::Frontend, 1), Pusher::new(frontend_tx))
1068            .await;
1069        pushers
1070            .insert(
1071                PusherId::new(Role::Flownode, u64::MIN),
1072                Pusher::new(flownode_tx),
1073            )
1074            .await;
1075
1076        let msg = MailboxMessage {
1077            id: 42,
1078            subject: "broadcast-test".to_string(),
1079            timestamp_millis: 123,
1080            ..Default::default()
1081        };
1082
1083        pushers.broadcast(Role::Frontend, &msg).await.unwrap();
1084
1085        let received = frontend_rx.recv().await.unwrap().unwrap();
1086        let mailbox_message = received.mailbox_message.unwrap();
1087        assert_eq!(mailbox_message.id, 0);
1088        assert_eq!(mailbox_message.subject, "broadcast-test");
1089        assert!(datanode_rx.try_recv().is_err());
1090        assert!(flownode_rx.try_recv().is_err());
1091    }
1092
1093    #[test]
1094    fn test_handler_group_builder() {
1095        let group = HeartbeatHandlerGroupBuilder::new(Pushers::default())
1096            .add_default_handlers()
1097            .build()
1098            .unwrap();
1099
1100        let handlers = group.handlers;
1101        let names = [
1102            "ResponseHeaderHandler",
1103            "DatanodeKeepLeaseHandler",
1104            "FlownodeKeepLeaseHandler",
1105            "CheckLeaderHandler",
1106            "OnLeaderStartHandler",
1107            "ExtractStatHandler",
1108            "CollectDatanodeClusterInfoHandler",
1109            "CollectFrontendClusterInfoHandler",
1110            "CollectFlownodeClusterInfoHandler",
1111            "MailboxHandler",
1112            "FilterInactiveRegionStatsHandler",
1113            "CollectLeaderRegionHandler",
1114            "CollectTopicStatsHandler",
1115            "CollectStatsHandler",
1116            "RemapFlowPeerHandler",
1117        ];
1118        assert_eq!(names.len(), handlers.len());
1119        for (handler, name) in handlers.iter().zip(names) {
1120            assert_eq!(handler.name, name);
1121        }
1122    }
1123
1124    #[test]
1125    fn test_handler_group_builder_add_before() {
1126        let mut builder =
1127            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1128        builder
1129            .add_handler_before(
1130                "FilterInactiveRegionStatsHandler",
1131                CollectStatsHandler::default(),
1132            )
1133            .unwrap();
1134
1135        let group = builder.build().unwrap();
1136        let handlers = group.handlers;
1137        let names = [
1138            "ResponseHeaderHandler",
1139            "DatanodeKeepLeaseHandler",
1140            "FlownodeKeepLeaseHandler",
1141            "CheckLeaderHandler",
1142            "OnLeaderStartHandler",
1143            "ExtractStatHandler",
1144            "CollectDatanodeClusterInfoHandler",
1145            "CollectFrontendClusterInfoHandler",
1146            "CollectFlownodeClusterInfoHandler",
1147            "MailboxHandler",
1148            "CollectStatsHandler",
1149            "FilterInactiveRegionStatsHandler",
1150            "CollectLeaderRegionHandler",
1151            "CollectTopicStatsHandler",
1152            "CollectStatsHandler",
1153            "RemapFlowPeerHandler",
1154        ];
1155        assert_eq!(names.len(), handlers.len());
1156        for (handler, name) in handlers.iter().zip(names) {
1157            assert_eq!(handler.name, name);
1158        }
1159    }
1160
1161    #[test]
1162    fn test_handler_group_builder_add_before_first() {
1163        let mut builder =
1164            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1165        builder
1166            .add_handler_before("ResponseHeaderHandler", CollectStatsHandler::default())
1167            .unwrap();
1168
1169        let group = builder.build().unwrap();
1170        let handlers = group.handlers;
1171        let names = [
1172            "CollectStatsHandler",
1173            "ResponseHeaderHandler",
1174            "DatanodeKeepLeaseHandler",
1175            "FlownodeKeepLeaseHandler",
1176            "CheckLeaderHandler",
1177            "OnLeaderStartHandler",
1178            "ExtractStatHandler",
1179            "CollectDatanodeClusterInfoHandler",
1180            "CollectFrontendClusterInfoHandler",
1181            "CollectFlownodeClusterInfoHandler",
1182            "MailboxHandler",
1183            "FilterInactiveRegionStatsHandler",
1184            "CollectLeaderRegionHandler",
1185            "CollectTopicStatsHandler",
1186            "CollectStatsHandler",
1187            "RemapFlowPeerHandler",
1188        ];
1189        assert_eq!(names.len(), handlers.len());
1190        for (handler, name) in handlers.iter().zip(names) {
1191            assert_eq!(handler.name, name);
1192        }
1193    }
1194
1195    #[test]
1196    fn test_handler_group_builder_add_after() {
1197        let mut builder =
1198            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1199        builder
1200            .add_handler_after("MailboxHandler", CollectStatsHandler::default())
1201            .unwrap();
1202
1203        let group = builder.build().unwrap();
1204        let handlers = group.handlers;
1205        let names = [
1206            "ResponseHeaderHandler",
1207            "DatanodeKeepLeaseHandler",
1208            "FlownodeKeepLeaseHandler",
1209            "CheckLeaderHandler",
1210            "OnLeaderStartHandler",
1211            "ExtractStatHandler",
1212            "CollectDatanodeClusterInfoHandler",
1213            "CollectFrontendClusterInfoHandler",
1214            "CollectFlownodeClusterInfoHandler",
1215            "MailboxHandler",
1216            "CollectStatsHandler",
1217            "FilterInactiveRegionStatsHandler",
1218            "CollectLeaderRegionHandler",
1219            "CollectTopicStatsHandler",
1220            "CollectStatsHandler",
1221            "RemapFlowPeerHandler",
1222        ];
1223        assert_eq!(names.len(), handlers.len());
1224        for (handler, name) in handlers.iter().zip(names) {
1225            assert_eq!(handler.name, name);
1226        }
1227    }
1228
1229    #[test]
1230    fn test_handler_group_builder_add_after_last() {
1231        let mut builder =
1232            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1233        builder
1234            .add_handler_after("CollectStatsHandler", ResponseHeaderHandler)
1235            .unwrap();
1236
1237        let group = builder.build().unwrap();
1238        let handlers = group.handlers;
1239        let names = [
1240            "ResponseHeaderHandler",
1241            "DatanodeKeepLeaseHandler",
1242            "FlownodeKeepLeaseHandler",
1243            "CheckLeaderHandler",
1244            "OnLeaderStartHandler",
1245            "ExtractStatHandler",
1246            "CollectDatanodeClusterInfoHandler",
1247            "CollectFrontendClusterInfoHandler",
1248            "CollectFlownodeClusterInfoHandler",
1249            "MailboxHandler",
1250            "FilterInactiveRegionStatsHandler",
1251            "CollectLeaderRegionHandler",
1252            "CollectTopicStatsHandler",
1253            "CollectStatsHandler",
1254            "ResponseHeaderHandler",
1255            "RemapFlowPeerHandler",
1256        ];
1257        assert_eq!(names.len(), handlers.len());
1258        for (handler, name) in handlers.iter().zip(names) {
1259            assert_eq!(handler.name, name);
1260        }
1261    }
1262
1263    #[test]
1264    fn test_handler_group_builder_replace() {
1265        let mut builder =
1266            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1267        builder
1268            .replace_handler("MailboxHandler", CollectStatsHandler::default())
1269            .unwrap();
1270
1271        let group = builder.build().unwrap();
1272        let handlers = group.handlers;
1273        let names = [
1274            "ResponseHeaderHandler",
1275            "DatanodeKeepLeaseHandler",
1276            "FlownodeKeepLeaseHandler",
1277            "CheckLeaderHandler",
1278            "OnLeaderStartHandler",
1279            "ExtractStatHandler",
1280            "CollectDatanodeClusterInfoHandler",
1281            "CollectFrontendClusterInfoHandler",
1282            "CollectFlownodeClusterInfoHandler",
1283            "CollectStatsHandler",
1284            "FilterInactiveRegionStatsHandler",
1285            "CollectLeaderRegionHandler",
1286            "CollectTopicStatsHandler",
1287            "CollectStatsHandler",
1288            "RemapFlowPeerHandler",
1289        ];
1290
1291        assert_eq!(names.len(), handlers.len());
1292        for (handler, name) in handlers.iter().zip(names) {
1293            assert_eq!(handler.name, name);
1294        }
1295    }
1296
1297    #[test]
1298    fn test_handler_group_builder_replace_last() {
1299        let mut builder =
1300            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1301        builder
1302            .replace_handler("CollectStatsHandler", ResponseHeaderHandler)
1303            .unwrap();
1304
1305        let group = builder.build().unwrap();
1306        let handlers = group.handlers;
1307        let names = [
1308            "ResponseHeaderHandler",
1309            "DatanodeKeepLeaseHandler",
1310            "FlownodeKeepLeaseHandler",
1311            "CheckLeaderHandler",
1312            "OnLeaderStartHandler",
1313            "ExtractStatHandler",
1314            "CollectDatanodeClusterInfoHandler",
1315            "CollectFrontendClusterInfoHandler",
1316            "CollectFlownodeClusterInfoHandler",
1317            "MailboxHandler",
1318            "FilterInactiveRegionStatsHandler",
1319            "CollectLeaderRegionHandler",
1320            "CollectTopicStatsHandler",
1321            "ResponseHeaderHandler",
1322            "RemapFlowPeerHandler",
1323        ];
1324
1325        assert_eq!(names.len(), handlers.len());
1326        for (handler, name) in handlers.iter().zip(names) {
1327            assert_eq!(handler.name, name);
1328        }
1329    }
1330
1331    #[test]
1332    fn test_handler_group_builder_replace_first() {
1333        let mut builder =
1334            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1335        builder
1336            .replace_handler("ResponseHeaderHandler", CollectStatsHandler::default())
1337            .unwrap();
1338
1339        let group = builder.build().unwrap();
1340        let handlers = group.handlers;
1341        let names = [
1342            "CollectStatsHandler",
1343            "DatanodeKeepLeaseHandler",
1344            "FlownodeKeepLeaseHandler",
1345            "CheckLeaderHandler",
1346            "OnLeaderStartHandler",
1347            "ExtractStatHandler",
1348            "CollectDatanodeClusterInfoHandler",
1349            "CollectFrontendClusterInfoHandler",
1350            "CollectFlownodeClusterInfoHandler",
1351            "MailboxHandler",
1352            "FilterInactiveRegionStatsHandler",
1353            "CollectLeaderRegionHandler",
1354            "CollectTopicStatsHandler",
1355            "CollectStatsHandler",
1356            "RemapFlowPeerHandler",
1357        ];
1358        assert_eq!(names.len(), handlers.len());
1359        for (handler, name) in handlers.iter().zip(names) {
1360            assert_eq!(handler.name, name);
1361        }
1362    }
1363
1364    #[test]
1365    fn test_handler_group_builder_handler_not_found() {
1366        let mut builder =
1367            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1368        let err = builder
1369            .add_handler_before("NotExists", CollectStatsHandler::default())
1370            .unwrap_err();
1371        assert_matches!(err, error::Error::HandlerNotFound { .. });
1372
1373        let err = builder
1374            .add_handler_after("NotExists", CollectStatsHandler::default())
1375            .unwrap_err();
1376        assert_matches!(err, error::Error::HandlerNotFound { .. });
1377
1378        let err = builder
1379            .replace_handler("NotExists", CollectStatsHandler::default())
1380            .unwrap_err();
1381        assert_matches!(err, error::Error::HandlerNotFound { .. });
1382    }
1383
1384    #[tokio::test]
1385    async fn test_pusher_drop() {
1386        let (tx, _rx) = mpsc::channel(1);
1387        let pusher = Pusher::new(tx);
1388        let mut deregister_signal_tx = pusher.deregister_signal_receiver.clone();
1389
1390        drop(pusher);
1391        deregister_signal_tx.changed().await.unwrap();
1392    }
1393
1394    #[tokio::test]
1395    async fn test_custom_handler_extension_reaches_response() {
1396        struct CustomExtensionHandler;
1397
1398        #[async_trait::async_trait]
1399        impl HeartbeatHandler for CustomExtensionHandler {
1400            fn is_acceptable(&self, role: Role) -> bool {
1401                role == Role::Frontend
1402            }
1403
1404            async fn handle(
1405                &self,
1406                _req: &HeartbeatRequest,
1407                _ctx: &mut Context,
1408                acc: &mut HeartbeatAccumulator,
1409            ) -> crate::error::Result<HandleControl> {
1410                acc.extensions
1411                    .insert("custom.key".to_string(), b"custom-value".to_vec());
1412                Ok(HandleControl::Continue)
1413            }
1414        }
1415
1416        let mut builder =
1417            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1418        builder.add_handler_last(CustomExtensionHandler);
1419
1420        let group = builder.build().unwrap();
1421
1422        let req = HeartbeatRequest {
1423            header: Some(RequestHeader::new(1, Role::Frontend, Default::default())),
1424            ..Default::default()
1425        };
1426        let ctx = TestEnv::new().ctx();
1427
1428        let res = group.handle(req, ctx).await.unwrap();
1429
1430        let extensions = res.extensions;
1431        assert_eq!(extensions.get("custom.key").unwrap(), b"custom-value");
1432    }
1433
1434    async fn full_pusher(
1435        pushers: &Pushers,
1436        id: PusherId,
1437    ) -> mpsc::Receiver<std::result::Result<HeartbeatResponse, tonic::Status>> {
1438        let (tx, rx) = mpsc::channel(1);
1439        tx.try_send(Ok(HeartbeatResponse::default())).unwrap();
1440        pushers.insert(id, Pusher::new(tx)).await;
1441        // Callers keep `rx` alive: dropping it would make the send fail instead of park.
1442        rx
1443    }
1444
1445    fn test_mailbox_message(subject: &str) -> MailboxMessage {
1446        MailboxMessage {
1447            id: 0,
1448            subject: subject.to_string(),
1449            timestamp_millis: 123,
1450            ..Default::default()
1451        }
1452    }
1453
1454    #[tokio::test]
1455    async fn test_pushers_push_does_not_fence_the_registry() {
1456        let pushers = Pushers::default();
1457
1458        let full_id = PusherId::new(Role::Datanode, 1);
1459        let _full_rx = full_pusher(&pushers, full_id).await;
1460
1461        let (healthy_tx, mut healthy_rx) = mpsc::channel(1);
1462        let healthy_id = PusherId::new(Role::Datanode, 2);
1463        pushers.insert(healthy_id, Pusher::new(healthy_tx)).await;
1464
1465        let msg = test_mailbox_message("fence-test");
1466
1467        let mut parked = Box::pin(pushers.push(full_id, msg.clone()));
1468        assert!(poll_immediate(parked.as_mut()).await.is_none());
1469
1470        let (writer_tx, _writer_rx) = mpsc::channel(1);
1471        let mut writer =
1472            Box::pin(pushers.insert(PusherId::new(Role::Datanode, 3), Pusher::new(writer_tx)));
1473        assert!(poll_immediate(writer.as_mut()).await.is_some());
1474
1475        let mut healthy = Box::pin(pushers.push(healthy_id, msg));
1476        assert!(poll_immediate(healthy.as_mut()).await.is_some());
1477        assert!(healthy_rx.try_recv().is_ok());
1478    }
1479
1480    #[tokio::test]
1481    async fn test_pushers_broadcast_does_not_fence_the_registry() {
1482        let pushers = Pushers::default();
1483
1484        let _full_rx = full_pusher(&pushers, PusherId::new(Role::Datanode, 1)).await;
1485        let (healthy_tx, _healthy_rx) = mpsc::channel(1);
1486        pushers
1487            .insert(PusherId::new(Role::Datanode, 2), Pusher::new(healthy_tx))
1488            .await;
1489
1490        let msg = test_mailbox_message("broadcast-fence-test");
1491        let mut parked = Box::pin(pushers.broadcast(Role::Datanode, &msg));
1492        assert!(poll_immediate(parked.as_mut()).await.is_none());
1493
1494        let (writer_tx, _writer_rx) = mpsc::channel(1);
1495        let mut writer =
1496            Box::pin(pushers.insert(PusherId::new(Role::Flownode, 1), Pusher::new(writer_tx)));
1497        assert!(poll_immediate(writer.as_mut()).await.is_some());
1498    }
1499
1500    #[tokio::test]
1501    async fn test_pusher_handle_does_not_fire_the_deregister_signal() {
1502        let (tx, _rx) = mpsc::channel(1);
1503        let pusher = Pusher::new(tx);
1504        let mut signal = pusher.deregister_signal_receiver.clone();
1505
1506        let handle = PusherHandle::from_pusher(&pusher);
1507        drop(handle);
1508
1509        assert!(
1510            tokio::time::timeout(Duration::from_millis(100), signal.changed())
1511                .await
1512                .is_err()
1513        );
1514
1515        // The real `Pusher` still owns the signal.
1516        drop(pusher);
1517        assert!(signal.changed().await.is_ok());
1518    }
1519}