mongock / mongock

Lightweight Java based migration tool

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

@ChangeSet executed before @ChangeUnit, ignoring order

EfreetSK opened this issue · comments

Description

When having a project with both @ChangeSet and @ChangeUnit, the @ChangeUnit is executed first, ignoring order.

We started using Mongock in the version 4 so we have a legacy @ChangeSets in our code. As suggested on a migration page, we kept existing @ChangeSets as they are and started using @ChangeUnit instead for future changes. However, when our QA department needed to re-create the database, the execution fails because the new changes (ChangeUnits) were executed first

PRIORITY

NORMAL

Version and environment

Mongock

  • Mongock version: 5.3.4
  • Modules involved: springboot, webflux, standalone, MongoDB, mongodb-sync-v4-driver,
  • How Mongock is used(builder or annotation approach, etc.): not sure how to answer, we use annotations, check demo project

Environment

  • Framework and libraries versions. Especially those that affect directly to Mongock(Spring, Spring data, MongoDB driver, etc.)
    • org.springframework.boot: 3.1.3
    • spring-webflux: 6.0.11
    • spring-data-mongodb: 4.1.3
    • Java 17.0.8.1
    • mongodb driver: 4.9.1
  • Infrastructure: plain Java application

Steps to Reproduce

  1. Create a @ChangeLog with @ChangeSet, set it order 0001
  2. Create a @ChangeUnit, set it order 0002
  3. Start the application
  4. Application crashes because the @ChangeUnit was executed first and order was ignored. Example exception:
    io.mongock.api.exception.MongockException: io.mongock.api.exception.MongockException: Error in method[DatabaseChangeLog.myFirstChangeLog] : Command failed with error 48 (NamespaceExists): 'Collection already exists. NS: testing-mongock.helloMongock' on server 127.0.0.1:27017. The full response is {"ok": 0.0, "errmsg": "Collection already exists. NS: testing-mongock.helloMongock", "code": 48, "codeName": "NamespaceExists", "$clusterTime": {"clusterTime": {"$timestamp": {"t": 1697099934, "i": 5}}, "signature": {"hash": {"$binary": {"base64": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "subType": "00"}}, "keyId": 0}}, "operationTime": {"$timestamp": {"t": 1697099934, "i": 5}}}

Behaviour

I'd expect that legacy @ChangeLogs and new @ChangeUnits can coexist, respecting each others order

Actual behavior: [What actually happens]

It looks like @ChangeUnits are executed first and order isn't respected

Link to repository using Mongock

I created a simple project to reproduce this:
https://github.com/EfreetSK/mongock-issue

Additional context

As far as I know this wasn't an issue before, we have other project which mixes @ChangeLog and @ChangeUnit. But it's been some time ago since we tried to recreate the whole database so maybe we just didn't notice.
Notice that we are using some adaptions in RootApplicationContext but hopefully this shouldn't be related to this

Hello @EfreetSK , this seem an important one. We'll take a look shortly.

Hello @EfreetSK , after review your provided project and the Mongock's current behaviour, the fix for your project is setting the order in the legacy @ChangeLog annotation, this way:

@ChangeLog(order = "0001")
public class DatabaseChangeLog {
    @ChangeSet(order = "0001", id = "0001", author = "test")
    public void myFirstChangeLog(MongoDatabase db) {
        db.createCollection("helloMongock");
    }
}

Note that the order should be lower than the order of your new @ChangeUnit classes (alphabetical order).

If you have multiple ChangeLog classes, please ensure that you set the order attribute in all of them.

Please let us know if it works for you.

We will update documentation to clarify the upgrade to v5 guide.

Many thanks.

@osantana85 Thank you for your reply. You're right, setting the order of @ChangeLog solves my issue, thank you!

Maybe for others who are reading this, I was wondering what should be the order of @ChangeUnit if there are multiple @ChangeSets. So f.e. let's have a @ChangeLog like this

@ChangeLog(order = "0001")
public class DatabaseChangeLog {
    @ChangeSet(order = "0001", id = "0001", author = "test")
    public void myFirstChangeSet(MongoDatabase db) {
        db.createCollection("helloMongock");
    }

    @ChangeSet(order = "0002", id = "0002", author = "test")
    public void mySecondChangeSet(MongoDatabase db) {
        db.createCollection("mySecondCollection");
    }
}

And I was wondering what should be the @ChangeUnit order now, 0002 (as a second class to be executed) or 0003 (as a third 'change set' to be executed). I tried it and the answer is 0003

@ChangeUnit(id="0003", order = "0003", author = "test")
public static class MyFirstChangeUnit {