Skip to content

Commit

Permalink
feat(gateway): inform project owner about running state (#1194)
Browse files Browse the repository at this point in the history
* feat(gateway): inform project owner about running state

Now, if `cargo shuttle project start` fails because the
existing project is owned by the caller, the information
from `cargo shuttle project status` is automatically displayed.
Depending on the running state, different hints are provided.

Extends #1192

* Improve PR #1194
  • Loading branch information
thass0 authored Sep 5, 2023
1 parent 6ff0f19 commit 2fa1db3
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 13 deletions.
17 changes: 11 additions & 6 deletions common/src/models/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Display for ApiError {

impl std::error::Error for ApiError {}

#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display)]
#[derive(Debug, Clone, PartialEq, Eq, strum::Display)]
pub enum ErrorKind {
KeyMissing,
BadHost,
Expand All @@ -42,7 +42,10 @@ pub enum ErrorKind {
ProjectNotFound,
InvalidProjectName,
ProjectAlreadyExists,
ProjectAlreadyRunning,
/// Contains a message describing a running state of the project.
/// Used if the project already exists but is owned
/// by the caller, which means they can modify the project.
OwnProjectAlreadyExists(String),
ProjectNotReady,
ProjectUnavailable,
CustomDomainNotFound,
Expand Down Expand Up @@ -98,10 +101,12 @@ impl From<ErrorKind> for ApiError {
StatusCode::BAD_REQUEST,
"a project with the same name already exists",
),
ErrorKind::ProjectAlreadyRunning => (
StatusCode::BAD_REQUEST,
"it looks like your project is already running. You can find out more with `cargo shuttle project status`",
),
ErrorKind::OwnProjectAlreadyExists(message) => {
return Self {
message,
status_code: StatusCode::BAD_REQUEST.as_u16(),
}
}
ErrorKind::InvalidCustomDomain => (StatusCode::BAD_REQUEST, "invalid custom domain"),
ErrorKind::CustomDomainNotFound => (StatusCode::NOT_FOUND, "custom domain not found"),
ErrorKind::CustomDomainAlreadyExists => {
Expand Down
2 changes: 1 addition & 1 deletion gateway/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl Error {
}

pub fn kind(&self) -> ErrorKind {
self.kind
self.kind.clone()
}
}

Expand Down
42 changes: 36 additions & 6 deletions gateway/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use once_cell::sync::Lazy;
use opentelemetry::global;
use opentelemetry_http::HeaderInjector;
use shuttle_common::backends::headers::{XShuttleAccountName, XShuttleAdminSecret};
use shuttle_common::models::project::State;
use sqlx::error::DatabaseError;
use sqlx::migrate::Migrator;
use sqlx::sqlite::SqlitePool;
Expand Down Expand Up @@ -480,10 +481,39 @@ impl GatewayService {
state: project,
})
} else {
// Otherwise it already exists. Because the caller of this
// command is the project owner, this means that the project
// is already running.
Err(Error::from_kind(ErrorKind::ProjectAlreadyRunning))
// Otherwise it already exists. Because the caller of this command is the
// project owner, this means that the project is already in some running state.
let state = State::from(project);
let message = match state {
// Ongoing processes.
State::Creating { .. }
| State::Attaching { .. }
| State::Recreating { .. }
| State::Starting { .. }
| State::Restarting { .. }
| State::Stopping
| State::Rebooting
| State::Destroying => {
format!("project '{project_name}' is already {state}. You can check the status again using `cargo shuttle project status`.")
}
// Use different message than the default for `State::Ready`.
State::Ready => {
format!("project '{project_name}' is already running")
}
State::Started | State::Destroyed => {
format!("project '{project_name}' is already {state}. Try using `cargo shuttle project restart` instead.")
}
State::Stopped => {
format!("project '{project_name}' is idled. Find out more about idle projects here: \
https://docs.shuttle.rs/getting-started/idle-projects")
}
State::Errored { message } => {
format!("project '{project_name}' is in an errored state.\nproject message: {message}")
}
};
Err(Error::from_kind(ErrorKind::OwnProjectAlreadyExists(
message,
)))
}
} else {
// Check if project name is valid according to new rules if it
Expand Down Expand Up @@ -1023,7 +1053,7 @@ pub mod tests {
assert!(matches!(
svc.create_project(matrix.clone(), neo, false, 0).await,
Err(Error {
kind: ErrorKind::ProjectAlreadyRunning,
kind: ErrorKind::OwnProjectAlreadyExists(_),
..
})
));
Expand Down Expand Up @@ -1060,7 +1090,7 @@ pub mod tests {
assert!(matches!(
svc.create_project(matrix, trinity, true, 0).await,
Err(Error {
kind: ErrorKind::ProjectAlreadyRunning,
kind: ErrorKind::OwnProjectAlreadyExists(_),
..
})
));
Expand Down

0 comments on commit 2fa1db3

Please sign in to comment.