mongodb/sync/client.rs
1pub mod session;
2
3use super::Database;
4use crate::{
5 concern::{ReadConcern, WriteConcern},
6 error::Result,
7 options::{ClientOptions, DatabaseOptions, SelectionCriteria},
8 Client as AsyncClient,
9};
10
11/// This is the main entry point for the synchronous API. A `Client` is used to connect to a MongoDB
12/// cluster. By default, it will monitor the topology of the cluster, keeping track of any changes,
13/// such as servers being added or removed.
14///
15/// `Client` is a wrapper around the asynchronous [`mongodb::Client`](../struct.Client.html), and it
16/// starts up a tokio runtime internally to run that wrapped client on.
17///
18/// `Client` uses [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) internally,
19/// so it can safely be shared across threads. For example:
20///
21/// ```rust
22/// # use mongodb::{bson::Document, sync::Client, error::Result};
23/// #
24/// # fn start_workers() -> Result<()> {
25/// let client = Client::with_uri_str("mongodb://example.com")?;
26///
27/// for i in 0..5 {
28/// let client_ref = client.clone();
29///
30/// std::thread::spawn(move || {
31/// let collection = client_ref.database("items").collection::<Document>(&format!("coll{}", i));
32///
33/// // Do something with the collection
34/// });
35/// }
36/// #
37/// # // Technically we should join the threads here, but for the purpose of the example, we'll just
38/// # // sleep for a bit.
39/// # std::thread::sleep(std::time::Duration::from_secs(3));
40/// # Ok(())
41/// # }
42/// ```
43///
44/// ## TCP Keepalive
45/// TCP keepalive is enabled by default with ``tcp_keepalive_time`` set to 120 seconds. The
46/// driver does not set ``tcp_keepalive_intvl``. See the
47/// [MongoDB Diagnostics FAQ keepalive section](https://www.mongodb.com/docs/manual/faq/diagnostics/#does-tcp-keepalive-time-affect-mongodb-deployments)
48/// for instructions on setting these values at the system level.
49///
50/// ## Clean shutdown
51/// Because Rust has no async equivalent of `Drop`, values that require server-side cleanup when
52/// dropped spawn a new async task to perform that cleanup. This can cause two potential issues:
53///
54/// * Drop tasks pending or in progress when the async runtime shuts down may not complete, causing
55/// server-side resources to not be freed.
56/// * Drop tasks may run at an arbitrary time even after no `Client` values exist, making it hard to
57/// reason about associated resources (e.g. event handlers).
58///
59/// To address these issues, we highly recommend you use [`Client::shutdown`] in the termination
60/// path of your application. This will ensure that outstanding resources have been cleaned up and
61/// terminate internal worker tasks before returning. Please note that `shutdown` will wait for
62/// _all_ outstanding resource handles to be dropped, so they must either have been dropped before
63/// calling `shutdown` or in a concurrent task; see the documentation of `shutdown` for more
64/// details.
65
66#[derive(Clone, Debug)]
67pub struct Client {
68 pub(crate) async_client: AsyncClient,
69}
70
71impl From<AsyncClient> for Client {
72 fn from(async_client: AsyncClient) -> Self {
73 Self { async_client }
74 }
75}
76
77impl Client {
78 /// Creates a new `Client` connected to the cluster specified by `uri`. `uri` must be a valid
79 /// MongoDB connection string.
80 ///
81 /// See the documentation on
82 /// [`ClientOptions::parse`](../options/struct.ClientOptions.html#method.parse) for more
83 /// details.
84 pub fn with_uri_str(uri: impl AsRef<str>) -> Result<Self> {
85 let async_client =
86 crate::sync::TOKIO_RUNTIME.block_on(AsyncClient::with_uri_str(uri.as_ref()))?;
87 Ok(Self { async_client })
88 }
89
90 /// Creates a new `Client` connected to the cluster specified by `options`.
91 pub fn with_options(options: ClientOptions) -> Result<Self> {
92 let async_client = AsyncClient::with_options(options)?;
93 Ok(Self { async_client })
94 }
95
96 /// Gets the default selection criteria the `Client` uses for operations..
97 pub fn selection_criteria(&self) -> Option<&SelectionCriteria> {
98 self.async_client.selection_criteria()
99 }
100
101 /// Gets the default read concern the `Client` uses for operations.
102 pub fn read_concern(&self) -> Option<&ReadConcern> {
103 self.async_client.read_concern()
104 }
105
106 /// Gets the default write concern the `Client` uses for operations.
107 pub fn write_concern(&self) -> Option<&WriteConcern> {
108 self.async_client.write_concern()
109 }
110
111 /// Gets a handle to a database specified by `name` in the cluster the `Client` is connected to.
112 /// The `Database` options (e.g. read preference and write concern) will default to those of the
113 /// `Client`.
114 ///
115 /// This method does not send or receive anything across the wire to the database, so it can be
116 /// used repeatedly without incurring any costs from I/O.
117 pub fn database(&self, name: &str) -> Database {
118 Database::new(self.async_client.database(name))
119 }
120
121 /// Gets a handle to a database specified by `name` in the cluster the `Client` is connected to.
122 /// Operations done with this `Database` will use the options specified by `options` by default
123 /// and will otherwise default to those of the `Client`.
124 ///
125 /// This method does not send or receive anything across the wire to the database, so it can be
126 /// used repeatedly without incurring any costs from I/O.
127 pub fn database_with_options(&self, name: &str, options: DatabaseOptions) -> Database {
128 Database::new(self.async_client.database_with_options(name, options))
129 }
130
131 /// Gets a handle to the default database specified in the `ClientOptions` or MongoDB connection
132 /// string used to construct this `Client`.
133 ///
134 /// If no default database was specified, `None` will be returned.
135 pub fn default_database(&self) -> Option<Database> {
136 self.async_client.default_database().map(Database::new)
137 }
138}