Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sequential migrations #27

Conversation

przemyslaw-dobrowolski-cl

This PR solved #25

przemyslaw-dobrowolski-cl added a commit to przemyslaw-dobrowolski-cl/gohan that referenced this pull request Mar 29, 2017
przemyslaw-dobrowolski-cl added a commit to przemyslaw-dobrowolski-cl/gohan that referenced this pull request Mar 29, 2017
przemyslaw-dobrowolski-cl added a commit to przemyslaw-dobrowolski-cl/gohan that referenced this pull request Mar 29, 2017
Copy link
Collaborator

@VojtechVitek VojtechVitek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this solve a following "race condition"?

  1. First developer merges PR with a newer migration (20170329) and deploys it.
  2. Second developer merges an older PR with migration (20170215) and deploys it?

The second migration would get lost and wouldn't get executed, since it has lower version number than the already applied migrations in the DB.

Goose compares migration versions as integers against the most recently applied migration version in the DB. It doesn't check if there's any migration "lost in the past". The library is not very complex.

I know that manual migration versioning is very annoying aspect of Goose right now, but at least it's stable and consistent. If you have a conflict (same version of migration) in the codebase, it errors out.

The time-based migration versions wouldn't work with the current Goose implementation. It would require large refactor to make it work

--

btw: I'm just leaving for vacation and won't be available in next 2 weeks. So I'll get back to this PR once I'm back. Feel free to ping me again.

Thanks for understanding.

@@ -173,7 +176,7 @@ language plpgsql;
A [sample Go migration 00002_users_add_email.go file](./example/migrations-go/00002_rename_root.go) looks like:

```go
package migrations
package main
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this change?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is golang requirement (https://tip.golang.org/pkg/plugin/).
[...] A plugin is a Go main package with exported functions [...]
Without this change, plugin do not compile correctly (resulting binary is not a valid ELF binary). Fortunately, this change does not break goose API.

przemyslaw-dobrowolski-cl added a commit to przemyslaw-dobrowolski-cl/gohan that referenced this pull request Mar 30, 2017
@przemyslaw-dobrowolski-cl
Copy link
Author

In order to eliminate migration collisions we have to maintain only sequential migration from the very beginning:

  1. We start with empty database - version 0.
  2. Developer A decides to add new schema to DB so he creates a new sequential migration:
    goose create-next initial go
    => 1_initial.go (made by dev. A)
  3. At the same time, different developer B also decides to create an initial change to DB schema:
    goose create-next initial go
    => 1_initial.go (made by dev. B)
  4. They both make changes and decide to commit changes to repository.
  5. One will succeed. The other merge will fail, rebase will also fail - since the same file already exists with different contents.
  6. They need to communicate and fix the migration which has not been yet applied.

The above procedure wouldn't work if any of the two developers use a date-based migration.

To not break backward compatibility, 'create' sub-command is not changed but instead a new 'create-next' is added. Developers should be instructed to use 'create-next' to be safe from migration collisions.

Another requirement for a developer is to commit a migration script at the same time database schema is changed so that different migration scripts and actual changes to database do not mix.

func Create(db *sql.DB, dir, name, migrationType string, sequential bool) error {
var version string
if !sequential {
version = time.Now().Format("20060102150405")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, what you just explained makes sense. However, the above line confused me. We shouldn't ever suggest version based on a time date.

Copy link
Collaborator

@VojtechVitek VojtechVitek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like there are still left overs from the other PR #26. Can you please remove them?

Let's keep this branch strictly to enforce sequential numbering, as a suggested practice.

There is confusing line at create.go:13, though:

version = time.Now().Format("20060102150405")

Is this a mistake? It shouldn't suggests timestamp but 0000 or 0001 as initial first migration version.

@VojtechVitek
Copy link
Collaborator

Superseded by #50.

Thanks for this PR anyway, you brought up a great point about goose versioning!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants