collab: Don't run migrations on startup (#44430)

Marshall Bowers created

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

Change summary

Dockerfile-collab                        |  4 -
crates/collab/README.md                  | 12 ---
crates/collab/k8s/migrate.template.yml   | 21 -----
crates/collab/src/db/tests.rs            | 17 ++--
crates/collab/src/db/tests/migrations.rs |  0 
crates/collab/src/lib.rs                 |  2 
crates/collab/src/llm.rs                 |  1 
crates/collab/src/llm/db.rs              | 98 --------------------------
crates/collab/src/main.rs                | 62 ---------------
script/create-migration                  |  3 
10 files changed, 10 insertions(+), 210 deletions(-)

Detailed changes

Dockerfile-collab 🔗

@@ -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"]

crates/collab/README.md 🔗

@@ -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.

crates/collab/k8s/migrate.template.yml 🔗

@@ -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

crates/collab/src/db/tests.rs 🔗

@@ -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>>,

crates/collab/src/lib.rs 🔗

@@ -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;
 

crates/collab/src/llm/db.rs 🔗

@@ -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
-        }
-    }
-}

crates/collab/src/main.rs 🔗

@@ -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"))
 }

script/create-migration 🔗

@@ -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"