Skip to main content

google_cloud_pubsub/subscriber/
client_builder.rs

1// Copyright 2026 Google LLC
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//     https://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 super::client::Subscriber;
16use crate::ClientBuilderResult as BuilderResult;
17use gaxi::options::ClientConfig;
18use google_cloud_auth::credentials::Credentials;
19
20// This is to handle large metadata when errors are returned for exactly once delivery.
21const MAX_INBOUND_METADATA_SIZE: u32 = 4 * 1024 * 1024; // 4MB API maximum metadata size
22
23/// A builder for [Subscriber].
24///
25/// # Example
26/// ```
27/// # use google_cloud_pubsub::client::Subscriber;
28/// # async fn sample() -> anyhow::Result<()> {
29/// let builder = Subscriber::builder();
30/// let client = builder
31///     .with_endpoint("https://pubsub.googleapis.com")
32///     .build()
33///     .await?;
34/// # Ok(()) }
35/// ```
36pub struct ClientBuilder {
37    pub(super) config: ClientConfig,
38}
39
40impl ClientBuilder {
41    pub(super) fn new() -> Self {
42        let mut config = ClientConfig::default();
43        config.grpc_max_header_list_size = Some(MAX_INBOUND_METADATA_SIZE);
44        Self { config }
45    }
46
47    /// Creates a new client.
48    ///
49    /// # Example
50    /// ```
51    /// # use google_cloud_pubsub::client::Subscriber;
52    /// # async fn sample() -> anyhow::Result<()> {
53    /// let client = Subscriber::builder().build().await?;
54    /// # Ok(()) }
55    /// ```
56    pub async fn build(self) -> BuilderResult<Subscriber> {
57        Subscriber::new(self).await
58    }
59
60    /// Sets the endpoint.
61    ///
62    /// # Example
63    /// ```
64    /// # use google_cloud_pubsub::client::Subscriber;
65    /// # async fn sample() -> anyhow::Result<()> {
66    /// let client = Subscriber::builder()
67    ///     .with_endpoint("https://private.googleapis.com")
68    ///     .build()
69    ///     .await?;
70    /// # Ok(()) }
71    /// ```
72    pub fn with_endpoint<V: Into<String>>(mut self, v: V) -> Self {
73        self.config.endpoint = Some(v.into());
74        self
75    }
76
77    /// Configure the universe domain.
78    ///
79    /// The universe domain is the default service domain for a given cloud universe.
80    /// The default value is "googleapis.com".
81    ///
82    /// # Example
83    /// ```
84    /// # use google_cloud_pubsub::client::Subscriber;
85    /// # async fn sample() -> anyhow::Result<()> {
86    /// let client = Subscriber::builder()
87    ///     .with_universe_domain("googleapis.com")
88    ///     .build()
89    ///     .await?;
90    /// # Ok(()) }
91    /// ```
92    pub fn with_universe_domain<V: Into<String>>(mut self, v: V) -> Self {
93        self.config.universe_domain = Some(v.into());
94        self
95    }
96
97    /// Configures the authentication credentials.
98    ///
99    /// More information about valid credentials types can be found in the
100    /// [google-cloud-auth] crate documentation.
101    ///
102    /// # Example
103    /// ```
104    /// # use google_cloud_pubsub::client::Subscriber;
105    /// # async fn sample() -> anyhow::Result<()> {
106    /// use google_cloud_auth::credentials::mds;
107    /// let client = Subscriber::builder()
108    ///     .with_credentials(
109    ///         mds::Builder::default()
110    ///             .with_scopes(["https://www.googleapis.com/auth/cloud-platform.read-only"])
111    ///             .build()?)
112    ///     .build()
113    ///     .await?;
114    /// # Ok(()) }
115    /// ```
116    ///
117    /// [google-cloud-auth]: https://docs.rs/google-cloud-auth
118    pub fn with_credentials<V: Into<Credentials>>(mut self, v: V) -> Self {
119        self.config.cred = Some(v.into());
120        self
121    }
122
123    /// Configure the number of subchannels used by the client.
124    ///
125    /// # Example
126    /// ```
127    /// # use google_cloud_pubsub::client::Subscriber;
128    /// # async fn sample() -> anyhow::Result<()> {
129    /// let count = std::thread::available_parallelism()?.get();
130    /// let client = Subscriber::builder()
131    ///     .with_grpc_subchannel_count(count)
132    ///     .build()
133    ///     .await?;
134    /// # Ok(()) }
135    /// ```
136    ///
137    /// gRPC-based clients may exhibit high latency if many requests need to be
138    /// demuxed over a single HTTP/2 connection (often called a *subchannel* in
139    /// gRPC).
140    ///
141    /// Consider using more subchannels if your application opens many message
142    /// streams. Consider using fewer subchannels if your application needs the
143    /// file descriptors for other purposes.
144    pub fn with_grpc_subchannel_count(mut self, v: usize) -> Self {
145        self.config.grpc_subchannel_count = Some(v);
146        self
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153    use google_cloud_auth::credentials::anonymous::Builder as Anonymous;
154
155    #[test]
156    fn defaults() {
157        let builder = ClientBuilder::new();
158        assert!(builder.config.endpoint.is_none(), "{:?}", builder.config);
159        assert!(builder.config.cred.is_none(), "{:?}", builder.config);
160        assert!(
161            builder.config.universe_domain.is_none(),
162            "{:?}",
163            builder.config
164        );
165        assert!(
166            builder.config.grpc_subchannel_count.is_none(),
167            "{:?}",
168            builder.config
169        );
170        assert_eq!(
171            builder.config.grpc_max_header_list_size,
172            Some(MAX_INBOUND_METADATA_SIZE)
173        );
174    }
175
176    #[test]
177    fn setters() {
178        let builder = ClientBuilder::new()
179            .with_endpoint("test-endpoint.com")
180            .with_universe_domain("test-ud.com")
181            .with_credentials(Anonymous::new().build())
182            .with_grpc_subchannel_count(16);
183        assert_eq!(
184            builder.config.endpoint,
185            Some("test-endpoint.com".to_string())
186        );
187        assert_eq!(
188            builder.config.universe_domain,
189            Some("test-ud.com".to_string())
190        );
191        assert!(builder.config.cred.is_some(), "{:?}", builder.config);
192        assert_eq!(builder.config.grpc_subchannel_count, Some(16));
193    }
194}