-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Add custom migration implementation #2878
Conversation
src/invidious/migration.cr
Outdated
@@ -0,0 +1,38 @@ | |||
abstract class Invidious::Migration | |||
macro inherited | |||
Invidious::Migrator.migrations << self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
migrations are automatically added to this list when the file is required which is why there's no need to do anything with migrations after they're defined.
src/invidious/migration.cr
Outdated
@db.transaction do |txn| | ||
up(txn.connection) | ||
track(txn.connection) | ||
@completed = true | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the core code that runs the migration
Thank you for your work! I'm definitively going to try it on https://github.com/iv-org/invidious/pull/2469/files#diff-64021f64c486d8a36eae29fce4c1b13e9c95f5cbb713ca7bcd26f8d38517eeb8 |
|
||
def up(conn : DB::Connection) | ||
conn.exec <<-SQL | ||
CREATE UNLOGGED TABLE IF NOT EXISTS public.videos |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that UNLOGGED
was a recent addition by @unixfox, most tables on the different instances haven't been altered. It would be preferrable to have a migration for that (ALTER TABLE ...
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left this as it was and made a new migration altering the table
src/invidious.cr
Outdated
@@ -111,6 +112,8 @@ end | |||
OUTPUT = CONFIG.output.upcase == "STDOUT" ? STDOUT : File.open(CONFIG.output, mode: "a") | |||
LOGGER = Invidious::LogHandler.new(OUTPUT, CONFIG.log_level) | |||
|
|||
# Run migrations | |||
Invidious::Database::Migrator.new(PG_DB).migrate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing to keep in mind with this right now is... if someone is deploying multiple instances of invidious at the same time, this could cause issues. I think we could have this code lock the migrations table so one instance will claim the migration rollout but I'm not sure if that will work. I've not personally seen it done that way. Typically migrations are run before the deploy. We could move this line to a separate file that people could run before deploying if they want? Is it even necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do the following:
- Check for migrations
- If migrations have to be run, exit with an informational message (and a specific error code)
- If
--migrate-db
is passed, run migrations
That way, it's at the discretion of the instance owner to do as they want: if invidious exits with specified error code, they can hook up a wrapper script to stop all other instances, run a backup, and then migrate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmmh this definitively need to be tackled properly. I'm running 10 instances of Invidious at the same time, so I don't want this to become an issue haha.
SQL | ||
end | ||
|
||
private def privacy_type_exists?(conn : DB::Connection) : Bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of the weird pgsql query, I extracted out this check to look for the privacy type and only creating it if this method returns false.
src/invidious/database/migrations/0008_create_playlists_table.cr
Outdated
Show resolved
Hide resolved
512209c
to
cf13c11
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
parser.on("--migrate", "Run any migrations") do | ||
Invidious::Database::Migrator.new(PG_DB).migrate | ||
exit | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a good idea, only issue is that it really messes with my flow of using docker-compose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right. We should probably make a wrapper script for that?
Also, we probably shouldn't exit
if migrations are run. Passing --migrate
would always bump the DB no matter what, without breaking the execution process. And we could make that the default on Docker, so owners of small instances aren't too surprised.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I'm concerned that we're going to roll out a breaking change to everyone with this PR. Everyone will update as normal and then find out that they can't run the service and will have to update their command, and I'm not sure the best way to roll that out.
What I'm going to do is leave this as it is, and remove the pending migration check. That way we can merge this change, it won't break anyone, and people can test out the migrations process. Then we can make a follow-up PR with the implementation that requires the migrations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am struggling to run these CLI arguments, when I type sudo docker exec -it invidious-invidious-1 invidious -v
I get
OCI runtime exec failed: exec failed: unable to start container process: exec: "invidious": executable file not found in $PATH: unknown
src/invidious.cr
Outdated
# Run migrations | ||
if Invidious::Database::Migrator.new(PG_DB).pending_migrations? | ||
puts "There are pending migrations. Run `invidious --migrate` to apply the migrations." | ||
exit 46 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You said use a specific error code 😛. But for real... what error code should I return?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know xD I'll have to double check that, to ensure that we don't use something that either kemal or crystal already do. (Also I'd have expected that you'd go with 42 xD)
This is so that we don't break deploys with this PR. Instead we only ship the 'invidious --migrate' cli command and let people test that. Maybe even ship a new migration that wouldn't break apps that don't run the migrations. Then we roll out the functionality that requires migrations.
@SamantazFox @TheFrenchGhosty Please don't merge this PR without extensive testing. I would even consider asking some people to test before merging that to the public. |
@unixfox Sure! |
# Run migrations | ||
if Invidious::Database::Migrator.new(PG_DB).pending_migrations? | ||
puts "There are pending migrations. Run `invidious --migrate` to apply the migrations." | ||
exit 46 | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"This is so that we don't break deploys with this PR."
Well, when we'll make any DB changes (like #2469), the code won't correspond to the DB anymore, so invidious will still be broken until the migration is done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an in-between, we could keep the check + message, but not exit (so it's easier to trace why invidious is broken).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made this change because it seems like the rollout of requiring migrations to have run needs more thought which would could give more attention in a followup PR. By removing that, we can merge in the migration code without worrying about breaking users
@SamantazFox Is there a blocker for this anymore now that it won't run migrations unless the CLI command is used? If this is merged we could talk further about how we want migrations to be done by end users |
I don't see any. I was waiting on @unixfox approval, as per his previous message. |
I'm not sure if I'll have time to try, you may merge anyway as it is not automatic yet. |
@SamantazFox Does this mean we can finally merge PRs that implement database changes? (after they're changed to work, obviously) |
No because it's not automatic yet. Merging them will brake invidious. |
Fixes #2620
Instead of adding a migration library that is unmaintained, restrictive, or we'd have to tweak anyways, why not make our own? As you can see it really doesn't take that much code to get a minimal version working.
This implementation has things to point out:
Feel free to push back on this, my feelings won't be hurt 😄