collab: Don't run migrations on startup (#44430)
This PR removes the step that applies migrations when Collab starts up, as migrations are now done as part of Cloud deployments. Release Notes: - N/A
This commit is contained in:
@@ -34,8 +34,4 @@ RUN apt-get update; \
|
||||
linux-perf binutils
|
||||
WORKDIR app
|
||||
COPY --from=builder /app/collab /app/collab
|
||||
COPY --from=builder /app/crates/collab/migrations /app/migrations
|
||||
COPY --from=builder /app/crates/collab/migrations_llm /app/migrations_llm
|
||||
ENV MIGRATIONS_PATH=/app/migrations
|
||||
ENV LLM_DATABASE_MIGRATIONS_PATH=/app/migrations_llm
|
||||
ENTRYPOINT ["/app/collab"]
|
||||
|
||||
@@ -63,15 +63,3 @@ Deployment is triggered by pushing to the `collab-staging` (or `collab-productio
|
||||
- `./script/deploy-collab production`
|
||||
|
||||
You can tell what is currently deployed with `./script/what-is-deployed`.
|
||||
|
||||
# Database Migrations
|
||||
|
||||
To create a new migration:
|
||||
|
||||
```sh
|
||||
./script/create-migration <name>
|
||||
```
|
||||
|
||||
Migrations are run automatically on service start, so run `foreman start` again. The service will crash if the migrations fail.
|
||||
|
||||
When you create a new migration, you also need to update the [SQLite schema](./migrations.sqlite/20221109000000_test_schema.sql) that is used for testing.
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
namespace: ${ZED_KUBE_NAMESPACE}
|
||||
name: ${ZED_MIGRATE_JOB_NAME}
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: migrator
|
||||
imagePullPolicy: Always
|
||||
image: ${ZED_IMAGE_ID}
|
||||
args:
|
||||
- migrate
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: database
|
||||
key: url
|
||||
@@ -3,22 +3,21 @@ mod channel_tests;
|
||||
mod contributor_tests;
|
||||
mod db_tests;
|
||||
mod extension_tests;
|
||||
mod migrations;
|
||||
|
||||
use crate::migrations::run_database_migrations;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicI32, Ordering::SeqCst};
|
||||
use std::time::Duration;
|
||||
|
||||
use super::*;
|
||||
use gpui::BackgroundExecutor;
|
||||
use parking_lot::Mutex;
|
||||
use rand::prelude::*;
|
||||
use sea_orm::ConnectionTrait;
|
||||
use sqlx::migrate::MigrateDatabase;
|
||||
use std::{
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicI32, Ordering::SeqCst},
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use self::migrations::run_database_migrations;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct TestDb {
|
||||
pub db: Option<Arc<Database>>,
|
||||
|
||||
@@ -3,8 +3,6 @@ pub mod auth;
|
||||
pub mod db;
|
||||
pub mod env;
|
||||
pub mod executor;
|
||||
pub mod llm;
|
||||
pub mod migrations;
|
||||
pub mod rpc;
|
||||
pub mod seed;
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pub mod db;
|
||||
@@ -1,98 +0,0 @@
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
pub use sea_orm::ConnectOptions;
|
||||
use sea_orm::{DatabaseConnection, DatabaseTransaction, IsolationLevel, TransactionTrait};
|
||||
|
||||
use crate::Result;
|
||||
use crate::db::TransactionHandle;
|
||||
use crate::executor::Executor;
|
||||
|
||||
/// The database for the LLM service.
|
||||
pub struct LlmDatabase {
|
||||
options: ConnectOptions,
|
||||
pool: DatabaseConnection,
|
||||
#[allow(unused)]
|
||||
executor: Executor,
|
||||
#[cfg(test)]
|
||||
runtime: Option<tokio::runtime::Runtime>,
|
||||
}
|
||||
|
||||
impl LlmDatabase {
|
||||
/// Connects to the database with the given options
|
||||
pub async fn new(options: ConnectOptions, executor: Executor) -> Result<Self> {
|
||||
sqlx::any::install_default_drivers();
|
||||
Ok(Self {
|
||||
options: options.clone(),
|
||||
pool: sea_orm::Database::connect(options).await?,
|
||||
executor,
|
||||
#[cfg(test)]
|
||||
runtime: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn options(&self) -> &ConnectOptions {
|
||||
&self.options
|
||||
}
|
||||
|
||||
pub async fn transaction<F, Fut, T>(&self, f: F) -> Result<T>
|
||||
where
|
||||
F: Send + Fn(TransactionHandle) -> Fut,
|
||||
Fut: Send + Future<Output = Result<T>>,
|
||||
{
|
||||
let body = async {
|
||||
let (tx, result) = self.with_transaction(&f).await?;
|
||||
match result {
|
||||
Ok(result) => match tx.commit().await.map_err(Into::into) {
|
||||
Ok(()) => Ok(result),
|
||||
Err(error) => Err(error),
|
||||
},
|
||||
Err(error) => {
|
||||
tx.rollback().await?;
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.run(body).await
|
||||
}
|
||||
|
||||
async fn with_transaction<F, Fut, T>(&self, f: &F) -> Result<(DatabaseTransaction, Result<T>)>
|
||||
where
|
||||
F: Send + Fn(TransactionHandle) -> Fut,
|
||||
Fut: Send + Future<Output = Result<T>>,
|
||||
{
|
||||
let tx = self
|
||||
.pool
|
||||
.begin_with_config(Some(IsolationLevel::ReadCommitted), None)
|
||||
.await?;
|
||||
|
||||
let mut tx = Arc::new(Some(tx));
|
||||
let result = f(TransactionHandle(tx.clone())).await;
|
||||
let tx = Arc::get_mut(&mut tx)
|
||||
.and_then(|tx| tx.take())
|
||||
.context("couldn't complete transaction because it's still in use")?;
|
||||
|
||||
Ok((tx, result))
|
||||
}
|
||||
|
||||
async fn run<F, T>(&self, future: F) -> Result<T>
|
||||
where
|
||||
F: Future<Output = Result<T>>,
|
||||
{
|
||||
#[cfg(test)]
|
||||
{
|
||||
if let Executor::Deterministic(executor) = &self.executor {
|
||||
executor.simulate_random_delay().await;
|
||||
}
|
||||
|
||||
self.runtime.as_ref().unwrap().block_on(future)
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
future.await
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::{Context as _, anyhow};
|
||||
use anyhow::anyhow;
|
||||
use axum::headers::HeaderMapExt;
|
||||
use axum::{
|
||||
Extension, Router,
|
||||
@@ -9,8 +9,6 @@ use axum::{
|
||||
|
||||
use collab::ServiceMode;
|
||||
use collab::api::CloudflareIpCountryHeader;
|
||||
use collab::llm::db::LlmDatabase;
|
||||
use collab::migrations::run_database_migrations;
|
||||
use collab::{
|
||||
AppState, Config, Result, api::fetch_extensions_from_blob_store_periodically, db, env,
|
||||
executor::Executor,
|
||||
@@ -19,7 +17,6 @@ use db::Database;
|
||||
use std::{
|
||||
env::args,
|
||||
net::{SocketAddr, TcpListener},
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
@@ -49,10 +46,6 @@ async fn main() -> Result<()> {
|
||||
Some("version") => {
|
||||
println!("collab v{} ({})", VERSION, REVISION.unwrap_or("unknown"));
|
||||
}
|
||||
Some("migrate") => {
|
||||
let config = envy::from_env::<Config>().expect("error loading config");
|
||||
setup_app_database(&config).await?;
|
||||
}
|
||||
Some("seed") => {
|
||||
let config = envy::from_env::<Config>().expect("error loading config");
|
||||
let db_options = db::ConnectOptions::new(config.database_url.clone());
|
||||
@@ -69,7 +62,7 @@ async fn main() -> Result<()> {
|
||||
Some("all") => ServiceMode::All,
|
||||
_ => {
|
||||
return Err(anyhow!(
|
||||
"usage: collab <version | migrate | seed | serve <api|collab|all>>"
|
||||
"usage: collab <version | seed | serve <api|collab|all>>"
|
||||
))?;
|
||||
}
|
||||
};
|
||||
@@ -90,7 +83,6 @@ async fn main() -> Result<()> {
|
||||
|
||||
if mode.is_collab() || mode.is_api() {
|
||||
setup_app_database(&config).await?;
|
||||
setup_llm_database(&config).await?;
|
||||
|
||||
let state = AppState::new(config, Executor::Production).await?;
|
||||
|
||||
@@ -211,25 +203,6 @@ async fn setup_app_database(config: &Config) -> Result<()> {
|
||||
let db_options = db::ConnectOptions::new(config.database_url.clone());
|
||||
let mut db = Database::new(db_options).await?;
|
||||
|
||||
let migrations_path = config.migrations_path.as_deref().unwrap_or_else(|| {
|
||||
#[cfg(feature = "sqlite")]
|
||||
let default_migrations = concat!(env!("CARGO_MANIFEST_DIR"), "/migrations.sqlite");
|
||||
#[cfg(not(feature = "sqlite"))]
|
||||
let default_migrations = concat!(env!("CARGO_MANIFEST_DIR"), "/migrations");
|
||||
|
||||
Path::new(default_migrations)
|
||||
});
|
||||
|
||||
let migrations = run_database_migrations(db.options(), migrations_path).await?;
|
||||
for (migration, duration) in migrations {
|
||||
log::info!(
|
||||
"Migrated {} {} {:?}",
|
||||
migration.version,
|
||||
migration.description,
|
||||
duration
|
||||
);
|
||||
}
|
||||
|
||||
db.initialize_notification_kinds().await?;
|
||||
|
||||
if config.seed_path.is_some() {
|
||||
@@ -239,37 +212,6 @@ async fn setup_app_database(config: &Config) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn setup_llm_database(config: &Config) -> Result<()> {
|
||||
let database_url = config
|
||||
.llm_database_url
|
||||
.as_ref()
|
||||
.context("missing LLM_DATABASE_URL")?;
|
||||
|
||||
let db_options = db::ConnectOptions::new(database_url.clone());
|
||||
let db = LlmDatabase::new(db_options, Executor::Production).await?;
|
||||
|
||||
let migrations_path = config
|
||||
.llm_database_migrations_path
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| {
|
||||
let default_migrations = concat!(env!("CARGO_MANIFEST_DIR"), "/migrations_llm");
|
||||
|
||||
Path::new(default_migrations)
|
||||
});
|
||||
|
||||
let migrations = run_database_migrations(db.options(), migrations_path).await?;
|
||||
for (migration, duration) in migrations {
|
||||
log::info!(
|
||||
"Migrated {} {} {:?}",
|
||||
migration.version,
|
||||
migration.description,
|
||||
duration
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_root(Extension(mode): Extension<ServiceMode>) -> String {
|
||||
format!("zed:{mode} v{VERSION} ({})", REVISION.unwrap_or("unknown"))
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
zed . \
|
||||
"crates/collab/migrations.sqlite/20221109000000_test_schema.sql" \
|
||||
"crates/collab/migrations/$(date -u +%Y%m%d%H%M%S)_$(echo $1 | sed 's/[^a-z0-9]/_/g').sql"
|
||||
Reference in New Issue
Block a user