• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tari-project / tari / 18097567115

29 Sep 2025 12:50PM UTC coverage: 58.554% (-2.3%) from 60.88%
18097567115

push

github

web-flow
chore(ci): switch rust toolchain to stable (#7524)

Description
switch rust toolchain to stable

Motivation and Context
use stable rust toolchain


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Standardized Rust toolchain on stable across CI workflows for more
predictable builds.
* Streamlined setup by removing unnecessary components and aligning
toolchain configuration with environment variables.
  * Enabled an environment flag to improve rustup behavior during CI.
* Improved coverage workflow consistency with dynamic toolchain
selection.

* **Tests**
* Removed nightly-only requirements, simplifying test commands and
improving compatibility.
* Expanded CI triggers to include ci-* branches for better pre-merge
validation.
* Maintained existing job logic while improving reliability and
maintainability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

66336 of 113291 relevant lines covered (58.55%)

551641.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.1
/base_layer/service_framework/src/stack.rs
1
// Copyright 2019 The Tari Project
2
//
3
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4
// following conditions are met:
5
//
6
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
// disclaimer.
8
//
9
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
10
// following disclaimer in the documentation and/or other materials provided with the distribution.
11
//
12
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
13
// products derived from this software without specific prior written permission.
14
//
15
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22

23
use futures::future;
24
use tari_shutdown::ShutdownSignal;
25

26
use crate::{
27
    context::{create_context_notifier_pair, ServiceHandles},
28
    initializer::{InitializerFn, ServiceInitializationError, ServiceInitializer},
29
    ServiceInitializerContext,
30
};
31

32
/// Responsible for building and collecting handles and (usually long-running) service futures.
33
/// `finish` is an async function which resolves once all the services are initialized, or returns
34
/// an error if any one of the services fails to initialize.
35
pub struct StackBuilder {
36
    initializers: Vec<Box<dyn ServiceInitializer + Send>>,
37
    shutdown_signal: ShutdownSignal,
38
}
39

40
impl StackBuilder {
41
    pub fn new(shutdown_signal: ShutdownSignal) -> Self {
4✔
42
        Self {
4✔
43
            initializers: Vec::new(),
4✔
44
            shutdown_signal,
4✔
45
        }
4✔
46
    }
4✔
47
}
48

49
impl StackBuilder {
50
    /// Add an impl of ServiceInitializer to the stack
51
    pub fn add_initializer<I>(self, initializer: I) -> Self
10✔
52
    where I: ServiceInitializer + Send + 'static {
10✔
53
        self.add_initializer_boxed(initializer)
10✔
54
    }
10✔
55

56
    /// Add an impl of ServiceInitializer to the stack
57
    pub fn add_initializer_fn<TFunc>(self, initializer: TFunc) -> Self
×
58
    where TFunc: FnOnce(ServiceInitializerContext) -> Result<(), ServiceInitializationError> + Send + 'static {
×
59
        self.add_initializer_boxed(InitializerFn::new(initializer))
×
60
    }
×
61

62
    /// Add a ServiceInitializer which has been boxed using `ServiceInitializer::boxed`
63
    pub fn add_initializer_boxed(mut self, initializer: impl ServiceInitializer + Send + 'static) -> Self {
10✔
64
        self.initializers.push(Box::new(initializer));
10✔
65
        self
10✔
66
    }
10✔
67

68
    /// Concurrently initialize the services. Once all service have been initialized, `notify_ready`
69
    /// is called, which completes initialization for those services. The resulting service handles are
70
    /// returned. If ANY of the services fail to initialize, an error is returned.
71
    pub async fn build(self) -> Result<ServiceHandles, ServiceInitializationError> {
4✔
72
        let StackBuilder {
73
            shutdown_signal,
4✔
74
            mut initializers,
4✔
75
        } = self;
4✔
76

77
        let (mut notifier, context) = create_context_notifier_pair(shutdown_signal);
4✔
78

79
        // Collect all the initialization futures
80
        let init_futures = initializers.iter_mut().map(|init| init.initialize(context.clone()));
10✔
81

82
        // Run all the initializers concurrently and check each Result returning an error
83
        // on the first one that failed.
84
        future::try_join_all(init_futures).await?;
4✔
85

86
        notifier.trigger();
4✔
87

88
        Ok(context.into_inner())
4✔
89
    }
4✔
90
}
91

92
#[cfg(test)]
93
mod test {
94
    use std::sync::{
95
        atomic::{AtomicUsize, Ordering},
96
        Arc,
97
    };
98

99
    use async_trait::async_trait;
100
    use futures::executor::block_on;
101
    use tari_shutdown::Shutdown;
102
    use tower::service_fn;
103

104
    use super::*;
105

106
    #[tokio::test]
107
    async fn service_defn_simple() {
1✔
108
        // This is less of a test and more of a demo of using the short-hand implementation of ServiceInitializer
109
        let simple_initializer = |_: ServiceInitializerContext| Ok(());
1✔
110

111
        let shutdown = Shutdown::new();
1✔
112

113
        let handles = StackBuilder::new(shutdown.to_signal())
1✔
114
            .add_initializer(simple_initializer)
1✔
115
            .build()
1✔
116
            .await;
1✔
117

118
        assert!(handles.is_ok());
1✔
119
    }
1✔
120

121
    #[derive(Clone)]
122
    struct DummyServiceHandle(usize);
123
    struct DummyInitializer {
124
        state: Arc<AtomicUsize>,
125
    }
126

127
    impl DummyInitializer {
128
        fn new(state: Arc<AtomicUsize>) -> Self {
1✔
129
            Self { state }
1✔
130
        }
1✔
131
    }
132

133
    #[async_trait]
134
    impl ServiceInitializer for DummyInitializer {
135
        async fn initialize(&mut self, context: ServiceInitializerContext) -> Result<(), ServiceInitializationError> {
2✔
136
            // Add a handle
137
            context.register_handle(DummyServiceHandle(123));
1✔
138

139
            // This demonstrates the chicken and egg problem with services and handles. Specifically,
140
            // that we have a service which requires the handles of other services to be able to
141
            // create its own handle. Here we wait for the handles_fut to resolve before continuing
142
            // to initialize the service.
143
            //
144
            // Critically, you should never wait for handles in the initialize method because
145
            // handles are only resolved after all initialization methods have completed.
146
            context.spawn_when_ready(|handles| async move {
1✔
147
                let handle = handles.get_handle::<DummyServiceHandle>().unwrap();
×
148
                assert_eq!(handle.0, 123);
×
149
                // Something which uses the handle
150
                service_fn(|_: ()| future::ok::<_, ()>(handle.0));
×
151
            });
×
152

153
            self.state.fetch_add(1, Ordering::SeqCst);
1✔
154
            Ok(())
1✔
155
        }
2✔
156
    }
157

158
    #[tokio::test]
159
    async fn service_stack_new() {
1✔
160
        let shared_state = Arc::new(AtomicUsize::new(0));
1✔
161

162
        let shutdown = Shutdown::new();
1✔
163
        let initializer = DummyInitializer::new(Arc::clone(&shared_state));
1✔
164

165
        let handles = block_on(
1✔
166
            StackBuilder::new(shutdown.to_signal())
1✔
167
                .add_initializer(initializer)
1✔
168
                .build(),
1✔
169
        )
170
        .unwrap();
1✔
171

172
        handles.get_handle::<DummyServiceHandle>().unwrap();
1✔
173

174
        assert_eq!(shared_state.load(Ordering::SeqCst), 1);
1✔
175
    }
1✔
176
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc