Skip to content

Commit

Permalink
Feature: remove tokio runtime from all resources (#680)
Browse files Browse the repository at this point in the history
* feat: remove runtime from resources

* fix: compile errors, comments

* fix: remove comment
  • Loading branch information
oddgrd authored Mar 6, 2023
1 parent 52096fc commit 3489e83
Show file tree
Hide file tree
Showing 10 changed files with 17 additions and 73 deletions.
1 change: 0 additions & 1 deletion resources/aws-rds/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ async-trait = "0.1.56"
paste = "1.0.7"
shuttle-service = { path = "../../service", version = "0.8.0", default-features = false }
sqlx = { version = "0.6.2", features = ["runtime-tokio-native-tls"] }
tokio = { version = "1.19.2", features = ["rt"] }

[features]
postgres = ["sqlx/postgres"]
Expand Down
17 changes: 5 additions & 12 deletions resources/aws-rds/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use shuttle_service::{
error::CustomError,
Factory, ResourceBuilder,
};
use tokio::runtime::Runtime;

macro_rules! aws_engine {
($feature:expr, $pool_path:path, $options_path:path, $struct_ident:ident) => {
Expand All @@ -24,22 +23,16 @@ macro_rules! aws_engine {
Self {}
}

async fn build(self, factory: &mut dyn Factory, runtime: &Runtime) -> Result<$pool_path, shuttle_service::Error> {
async fn build(self, factory: &mut dyn Factory) -> Result<$pool_path, shuttle_service::Error> {
let connection_string = factory
.get_db_connection_string(Type::AwsRds(AwsRdsEngine::$struct_ident))
.await?;

// A sqlx Pool cannot cross runtime boundaries, so make sure to create the Pool on the service end
let pool = runtime
.spawn(async move {
$options_path::new()
.min_connections(1)
.max_connections(5)
.connect(&connection_string)
.await
})
let pool = $options_path::new()
.min_connections(1)
.max_connections(5)
.connect(&connection_string)
.await
.map_err(CustomError::new)?
.map_err(CustomError::new)?;

Ok(pool)
Expand Down
1 change: 0 additions & 1 deletion resources/persist/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,3 @@ serde = { version = "1.0.0", features = ["derive"] }
shuttle-common = { path = "../../common", version = "0.8.0", default-features = false }
shuttle-service = { path = "../../service", version = "0.8.0", default-features = false }
thiserror = "1.0.32"
tokio = { version = "1.19.2", features = ["rt"] }
2 changes: 0 additions & 2 deletions resources/persist/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use std::io::BufReader;
use std::io::BufWriter;
use std::path::PathBuf;
use thiserror::Error;
use tokio::runtime::Runtime;

#[derive(Error, Debug)]
pub enum PersistError {
Expand Down Expand Up @@ -74,7 +73,6 @@ impl ResourceBuilder<PersistInstance> for Persist {
async fn build(
self,
factory: &mut dyn Factory,
_runtime: &Runtime,
) -> Result<PersistInstance, shuttle_service::Error> {
Ok(PersistInstance {
service_name: factory.get_service_name(),
Expand Down
1 change: 0 additions & 1 deletion resources/shared-db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ async-trait = "0.1.56"
mongodb = { version = "2.3.0", optional = true }
shuttle-service = { path = "../../service", version = "0.8.0", default-features = false }
sqlx = { version = "0.6.2", features = ["runtime-tokio-native-tls"], optional = true }
tokio = { version = "1.19.2", features = ["rt"] }

[features]
postgres = ["sqlx/postgres"]
35 changes: 7 additions & 28 deletions resources/shared-db/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#![doc = include_str!("../README.md")]

use tokio::runtime::Runtime;

use async_trait::async_trait;
use shuttle_service::{database, error::CustomError, Error, Factory, ResourceBuilder};

Expand All @@ -16,26 +14,16 @@ impl ResourceBuilder<sqlx::PgPool> for Postgres {
Self {}
}

async fn build(
self,
factory: &mut dyn Factory,
runtime: &Runtime,
) -> Result<sqlx::PgPool, Error> {
async fn build(self, factory: &mut dyn Factory) -> Result<sqlx::PgPool, Error> {
let connection_string = factory
.get_db_connection_string(database::Type::Shared(database::SharedEngine::Postgres))
.await?;

// A sqlx Pool cannot cross runtime boundaries, so make sure to create the Pool on the service end
let pool = runtime
.spawn(async move {
sqlx::postgres::PgPoolOptions::new()
.min_connections(1)
.max_connections(5)
.connect(&connection_string)
.await
})
let pool = sqlx::postgres::PgPoolOptions::new()
.min_connections(1)
.max_connections(5)
.connect(&connection_string)
.await
.map_err(CustomError::new)?
.map_err(CustomError::new)?;

Ok(pool)
Expand All @@ -53,11 +41,7 @@ impl ResourceBuilder<mongodb::Database> for MongoDb {
Self {}
}

async fn build(
self,
factory: &mut dyn Factory,
runtime: &Runtime,
) -> Result<mongodb::Database, crate::Error> {
async fn build(self, factory: &mut dyn Factory) -> Result<mongodb::Database, crate::Error> {
let connection_string = factory
.get_db_connection_string(database::Type::Shared(database::SharedEngine::MongoDb))
.await
Expand All @@ -69,12 +53,7 @@ impl ResourceBuilder<mongodb::Database> for MongoDb {
client_options.min_pool_size = Some(1);
client_options.max_pool_size = Some(5);

// A mongodb client cannot cross runtime boundaries, so make sure to create the client on the service end
let client = runtime
.spawn(async move { mongodb::Client::with_options(client_options) })
.await
.map_err(CustomError::new)?
.map_err(CustomError::new)?;
let client = mongodb::Client::with_options(client_options).map_err(CustomError::new)?;

// Return a handle to the database defined at the end of the connection string, which is the users provisioned
// database
Expand Down
1 change: 0 additions & 1 deletion resources/static-folder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ keywords = ["shuttle-service", "static-folder"]
[dependencies]
async-trait = "0.1.56"
shuttle-service = { path = "../../service", version = "0.8.0", default-features = false }
tokio = { version = "1.19.2", features = ["rt"] }

[dev-dependencies]
tempdir = "0.3.7"
Expand Down
22 changes: 4 additions & 18 deletions resources/static-folder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{
fs::rename,
path::{Path, PathBuf},
};
use tokio::runtime::Runtime;

pub struct StaticFolder<'a> {
/// The folder to reach at runtime. Defaults to `static`
Expand All @@ -33,11 +32,7 @@ impl<'a> ResourceBuilder<PathBuf> for StaticFolder<'a> {
Self { folder: "static" }
}

async fn build(
self,
factory: &mut dyn Factory,
_runtime: &Runtime,
) -> Result<PathBuf, shuttle_service::Error> {
async fn build(self, factory: &mut dyn Factory) -> Result<PathBuf, shuttle_service::Error> {
let folder = Path::new(self.folder);

// Prevent users from users from reading anything outside of their crate's build folder
Expand Down Expand Up @@ -171,8 +166,7 @@ mod tests {
// Call plugin
let static_folder = StaticFolder::new();

let runtime = tokio::runtime::Runtime::new().unwrap();
let actual_folder = static_folder.build(&mut factory, &runtime).await.unwrap();
let actual_folder = static_folder.build(&mut factory).await.unwrap();

assert_eq!(
actual_folder,
Expand All @@ -185,24 +179,19 @@ mod tests {
"Hello, test!",
"expected file content to match"
);

runtime.shutdown_background();
}

#[tokio::test]
#[should_panic(expected = "Cannot use an absolute path for a static folder")]
async fn cannot_use_absolute_path() {
let mut factory = MockFactory::new();
let static_folder = StaticFolder::new();
let runtime = tokio::runtime::Runtime::new().unwrap();

let _ = static_folder
.folder("/etc")
.build(&mut factory, &runtime)
.build(&mut factory)
.await
.unwrap();

runtime.shutdown_background();
}

#[tokio::test]
Expand All @@ -217,13 +206,10 @@ mod tests {
// Call plugin
let static_folder = StaticFolder::new();

let runtime = tokio::runtime::Runtime::new().unwrap();
let _ = static_folder
.folder("../escape")
.build(&mut factory, &runtime)
.build(&mut factory)
.await
.unwrap();

runtime.shutdown_background();
}
}
3 changes: 0 additions & 3 deletions service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,6 @@ pub trait Factory: Send + Sync {
/// You may want to create your own managed resource by implementing this trait for some builder `B` to construct resource `T`. [`Factory`] can be used to provision resources
/// on shuttle's servers if your resource will need any.
///
/// The biggest thing to look out for is that your resource object might panic when it crosses the boundary between the shuttle's backend runtime and the runtime
/// of services. These resources should be created on the passed in `runtime` for this trait to prevent these panics.
///
/// Your resource will be available on a [shuttle_service::main][main] function as follow:
/// ```
Expand Down Expand Up @@ -371,7 +369,6 @@ pub trait Factory: Send + Sync {
/// async fn build(
/// self,
/// factory: &mut dyn Factory,
/// _runtime: &Runtime,
/// ) -> Result<Resource, shuttle_service::Error> {
/// Ok(Resource { name: self.name })
/// }
Expand Down
7 changes: 1 addition & 6 deletions service/src/persist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::io::BufReader;
use std::io::BufWriter;
use std::path::PathBuf;
use thiserror::Error;
use tokio::runtime::Runtime;

#[derive(Error, Debug)]
pub enum PersistError {
Expand Down Expand Up @@ -70,11 +69,7 @@ impl ResourceBuilder<PersistInstance> for Persist {
Self {}
}

async fn build(
self,
factory: &mut dyn Factory,
_runtime: &Runtime,
) -> Result<PersistInstance, crate::Error> {
async fn build(self, factory: &mut dyn Factory) -> Result<PersistInstance, crate::Error> {
Ok(PersistInstance {
service_name: factory.get_service_name(),
})
Expand Down

0 comments on commit 3489e83

Please sign in to comment.