Programmatic migrations in golang for FoundationDB
Not every wants to use migrations on key/value stores. For those who do, this
database migration tool handles migrations for FoundationDB
For example, you have a service which relies on some information to be in the
database such as a list of exchanges to pull prices from and the symbols that
are listed on those exchanges.
Then, you support more exchanges and symbols:
We want this to programatically happen and want the migrations to be launched
before new code that needs them is running.
On Kubernetes, we run something like dumb-init
as our container command where first we run the migrations and then the API
server. With a healthcheck on the API server container, the load balancer won’t
flip traffic over to the new containers until they are all live (migrations run)
.
See MIT-License.md
clone this repo into $GOPATH/github.com/dkoston/foundationdb-migrations and run:make install
docker build -t fdbm .
docker run --name fdbm -it fdbm bash; fdbm
docker cp fdbm:/go/src/github.com/dkoston/foundationdb-migrations/cmd/fdbm/fdbm .
By default fdbm
will look in ./db/fdb.cluster
for a FoundationDB cluster
file.
Alternatively, you can pass in the cluster file location with-f <path/to/file.name>
when calling fdbm
.
For example:
fdbm -f /conf/fdb.cluster up
The fdb client requires you to define the API version. By default, we use 510
.
To specify a version, add it as a comment to fdb.cluster
as defined above or
you can pass in the fdb version with -v <version>
when calling fdbm
.
For example:
fdbm -v 510 up
By default, fdbm
will look in ./db/migrations
for migrations. To specify a
different directory when calling fdbm
use -m </path/to/migrations>
.
For example:
fdbm -m /configs/database/migrations up
You should create migrations using the fdbm
command so they contain all the
necessary features and take advantage of new features. Do not copy/paste old
migration file contents.
fdbm create <migration_name>
After creation, you need to edit the contents to actually do something.
Feel free to import github.com/dkoston/fdbm/lib/fdbm
into your applications
and use the public APIs.
When running migrations, fdbm
will look at the db/migrations directory and run
any migrations which have not been previously run.
To do so, run:
fdbm up
WARNING: not every migration can be easily rolled back. If you have changed the
db and your code, you will have to roll back both your db and the code. Also,
the ability to roll back migrations purely depends on your ability to write a
migration function that will return data to its previous state. Unlike SQL where
data is structured, your application may have altered the data in such a way
that it cannot be rolled back (hopefully not). USE AT YOUR OWN RISK.
fdbm down
The above command will rollback the last applied migration. To rollback multiple
, you will have to run the command multiple times.
For convience, you can rollback and re-run the last migration with:
fdbm redo
fdmb status
$ fdbm: migration status
$ Status Date File
$ =========================================================================
$ Success 20180529155230 db/migrations/20130106222315_and_again.go
$ Rolled back 20180529160754 db/migrations/20180529152851_test2.go
You will see the timestamp of when applied migrations were run against the db.
Anything listed as “Pending” has not yet been run.
fdbm dbversion
$ fdbm dbversion
$ fdbm: dbversion 003
This will print the number of the last migration run. i.e. (003_alter_the_data_from_one.go)
The file should contain 2 functions, one named XXXX_Up()
and one namedXXXX_Down()
where XXXX
is the migration number.
The function named XXXX_Up()
will be run with fdbm up
and then function
named XXXX_Down()
will be run with fdbm down
.
You may have other functions in the file but those are the two that fdbm
will
look for an run automatically with up
and down
.
The following file will set a key/value pair to hello: world
on fdbm up
and
then removethat key/value pair on fdbm down
:
package main
import (
"github.com/apple/foundationdb/bindings/go/src/fdb"
)
func Up_20130106222315(t fdb.Transactor) error {
_, err := t.Transact(func (tr fdb.Transaction) (ret interface{}, err error) {
tr.Set(fdb.Key("hello"), []byte("world"))
return
})
return err
}
func Down_20130106222315(t fdb.Transactor) error {
_, err := t.Transact(func (tr fdb.Transaction) (ret interface{}, err error) {
tr.Clear(fdb.Key("hello"))
return
})
return err
}
Thank you!
Thanks to those who built goose (which fdbm is based heavily on)