kakoc / mongodb_migrator

Mongodb migrations managing tool
Other
1 stars 2 forks source link

When the last migration fails and previous migrations were done in a previous run it also marks all previous migrations as failed too. #1

Open shandak opened 1 year ago

shandak commented 1 year ago

I have the next calls

let migrations: Vec<Box<dyn Migration>> = vec![
        Box::new(m0::M0 {}),
        Box::new(m1::M1 {}),
        Box::new(m2::M2 {}),
        Box::new(m3::M3 {}),
        Box::new(m4::M4 {}),
        Box::new(m5::M5 {}),
        Box::new(m6::M6 {}),
    ];

    mongodb_migrator::migrator::default::DefaultMigrator::new()
        .with_conn(mongo.db.clone())
        .with_migrations_vec(migrations)
        .up().await?;

When I run with M6 failing it returns the error Migration wasn't completed successfully - M6\n\t due to that, following it migrations: [\"M1\", \"M2\", \"M3\", \"M4\", \"M5\", \"M6\"] weren't executed and after that all mentioned migrations marked as Fail but they were done successfully before.

And by the way, looks like M0 ignored, right? Can it be counted too?

kakoc commented 1 year ago

Seems that I'm missing something. This is how I tried to emulate your issue based the description above:

use anyhow::{Error, Result};
use async_trait::async_trait;
use bson::Bson;
use futures::stream::StreamExt;
use serde_derive::{Deserialize, Serialize};
use testcontainers::{clients::Cli, images::mongo::Mongo, Container};

use mongodb_migrator::{migration::Migration, migration_record::MigrationRecord, migrator::Env};

pub async fn basic<'a>(node: &Container<'a, Cli, Mongo>) {
    let host_port = node.get_host_port(27017).unwrap();
    let url = format!("mongodb://localhost:{}/", host_port);
    let client = mongodb::Client::with_uri_str(url).await.unwrap();
    let db = client.database("test");

    let migrations: Vec<Box<dyn Migration>> = vec![
        Box::new(M0 {}),
        Box::new(M1 {}),
        Box::new(M2 {}),
        Box::new(M3 {}),
        Box::new(M4 {}),
        Box::new(M5 {}),
        Box::new(M6 {}),
    ];

    let r = mongodb_migrator::migrator::default::DefaultMigrator::new()
        .with_conn(db.clone())
        .with_migrations_vec(migrations)
        .up()
        .await;

    let ms = db
        .collection("migrations")
        .find(bson::doc! {}, None)
        .await
        .unwrap()
        .collect::<Vec<_>>()
        .await
        .into_iter()
        .map(|v| bson::from_bson::<MigrationRecord>(Bson::Document(v.unwrap())).unwrap())
        .collect::<Vec<MigrationRecord>>(); //.unwrap().find();

    dbg!(ms);
    dbg!(r);

    assert!(false);
}

struct M0 {}
struct M1 {}
struct M2 {}
struct M3 {}
struct M4 {}
struct M5 {}
struct M6 {}

#[async_trait]
impl Migration for M0 {
    async fn up(&self, env: Env) -> Result<()> {
        Ok(())
    }
}

#[async_trait]
impl Migration for M1 {
    async fn up(&self, env: Env) -> Result<()> {
        Ok(())
    }
}

#[async_trait]
impl Migration for M2 {
    async fn up(&self, env: Env) -> Result<()> {
        Ok(())
    }
}

#[async_trait]
impl Migration for M3 {
    async fn up(&self, env: Env) -> Result<()> {
        Ok(())
    }
}

#[async_trait]
impl Migration for M4 {
    async fn up(&self, env: Env) -> Result<()> {
        Ok(())
    }
}

#[async_trait]
impl Migration for M5 {
    async fn up(&self, env: Env) -> Result<()> {
        Ok(())
    }
}

#[async_trait]
impl Migration for M6 {
    async fn up(&self, env: Env) -> Result<()> {
        Err(Error::msg("foo"))
    }
}

I receive the following output(which is ok as I see):

[tests/basic/mod.rs:43] ms = [
    MigrationRecord {
        _id: "M0",
        start_date: Some(
            2023-06-07T16:05:37.804917270Z,
        ),
        end_date: Some(
            2023-06-07T16:05:37.849418022Z,
        ),
        status: Success,
        duration: Some(
            44,
        ),
    },
    MigrationRecord {
        _id: "M1",
        start_date: Some(
            2023-06-07T16:05:37.850124019Z,
        ),
        end_date: Some(
            2023-06-07T16:05:37.850524508Z,
        ),
        status: Success,
        duration: Some(
            0,
        ),
    },
    MigrationRecord {
        _id: "M2",
        start_date: Some(
            2023-06-07T16:05:37.850952763Z,
        ),
        end_date: Some(
            2023-06-07T16:05:37.851270642Z,
        ),
        status: Success,
        duration: Some(
            0,
        ),
    },
    MigrationRecord {
        _id: "M3",
        start_date: Some(
            2023-06-07T16:05:37.851604088Z,
        ),
        end_date: Some(
            2023-06-07T16:05:37.851926869Z,
        ),
        status: Success,
        duration: Some(
            0,
        ),
    },
    MigrationRecord {
        _id: "M4",
        start_date: Some(
            2023-06-07T16:05:37.852275063Z,
        ),
        end_date: Some(
            2023-06-07T16:05:37.852586985Z,
        ),
        status: Success,
        duration: Some(
            0,
        ),
    },
    MigrationRecord {
        _id: "M5",
        start_date: Some(
            2023-06-07T16:05:37.852883479Z,
        ),
        end_date: Some(
            2023-06-07T16:05:37.853171634Z,
        ),
        status: Success,
        duration: Some(
            0,
        ),
    },
    MigrationRecord {
        _id: "M6",
        start_date: Some(
            2023-06-07T16:05:37.853492024Z,
        ),
        end_date: Some(
            2023-06-07T16:05:37.853760251Z,
        ),
        status: Fail,
        duration: Some(
            0,
        ),
    },
]
[tests/basic/mod.rs:45] r = Err(
    FinishedAndSavedAsFail {
        migration_id: "M6",
        next_not_executed_migrations_ids: [],
    },
)

So can you create and share a broken test? It will be easier to reproduce, test for regressions in the future and fix an issue. I think you can do it even trough PR, as you wish

shandak commented 1 year ago

It's important to reproduce - run all migrations except the last, and do not create M6 at this moment. They have to pass. Then run migrations again but with added the latest failed.