Unfortunately it is normal because there isn’t anything we can do about it. When you hit ctrl-c it kills the java VM without enough warning for liquibase to finish what it is doing and properly clean up.
The normal flow is:
Mark databasechangeloglock table as locked to prevent multiple liquibase instances from updating the same database concurrently.
Begin transaction
Execute each change in a changeSet. Note: Most liquibase changes are DDL statements that autocommit
Insert into databasechangelog that changeSet ran
Commit transaction.
It sounds like in your case java was killed during step 4. The changes in step 3 were auto-committed, but the changeSet mark was not committed.
Unfortunately, I think the only way to prevent it is to not stop liquibase mid-update.
We just started using Liquibase and our QA ran into the following problem where aborting Liquibase mid-process leaves a lock hanging around as well as doesn’t properly log which changesets were successfully executed.
This is on Ubuntu 8.04 LTS running MySQL 5.0.51a
1. From command-line, start liquibase process, e.g. $ liquibase --changeLogFile=update.xml update
2. Hit Ctrl-C during process
3. After-effects: a. Leaves a DATABASECHANGELOGLOCK record b. Doesn’t properly record the last changeset that was executed successfully when abort occurred.
4. Trying to run the same command doesn’t work becuase of lock (which I can clear easilty with liquibase releaselocks) as well as will generate errors because it tries to execute a changeSet again, when in fact it was run already (i.e. an alter table command)
Is this normal behavior? Is there something else I should be doing to prevent this?
Unfortunately, it is normal because there isn’t anything we can do about it. When you hit ctrl-c it kills the java VM without enough warning for liquibase to finish what it is doing and properly clean up.
It’s not only just killing the process. What if the db connection is severed somehow, say from the database side, or the network went down. Basically anything which cause the liquibase process to barf out.
Anyways, I did add to each changeSet to try and make them more idempotent. E.g. any alter table changesets now first have a precondition checking if the column exists first already.
I think one improvement is if the DATABASECHANGELOG logged when it started and finished each changeset. I know the elapsed time is printed in the logs, but it would also be useful to have the info in the log table itself. In your flow, add step 2a. Insert into databasechangelog that changeSet is being run. Then step 4 would be update databasechangelog that changeSet ran.
We definitely could, although then you begin to get different logic between different databases. It may be worth implementing in a future revision, however, since it can be an issue.