Using :pg_advisory_lockecto migration lock strategy can cause long phoenix request delays (5s ) in phoenix dev environment. This is due to Phoenix.Ecto.CheckRepoStatus calling Ecto.Migrator.migrations/1, which runs under a migration lock.
Question: is it really necessary that this call chain runs under a migration lock? In most cases, it will just detect that there is nothing to do. And hey, itâs the dev environment weâre talking about, normally there should be no concurrent migrations.
To give you more context, let me explain in more detail: A standard phoenix web app contains a Phoenix.Ecto.CheckRepoStatus plug entry in its endpoint.ex thatâs active in dev environment. The plug is a convenience that checks if there are pending migrations. It calls Ecto.Migrator.migrations/1, which obtains the ecto migration lock. Under the :pg_advisory_lock strategy, when âEcto cannot obtain the lock due to another instance occupying the lock, Ecto will wait for 5 secondsâ. Oh oh. In dev environment, with CheckRepoStatus plug, you just need two web requests to hit your phoenix server at the very same time to get into that situation. We stumbled into it with a JS app that, after load, fired two simultaneous GraphQL requests. One of them would take 5s. We worked around it by tuning down the :migration_advisory_lock_retry_interval_ms setting from its default value of 5000 ms to 10 ms (just in dev). But maybe there are better options? It would be great if Ecto.Migrator.migrations/1 had an escape hatch so it didnât need a lock.
On the same hand, itâs the dev environment and normally there shouldnât be any concurrent indexes being built either (one of the things pg_advisory_lock enables). Whatâs the motivation behind using :pg_advisory_lock in development?
This was indeed my first attempt, to use :table_lock strategy in dev environment. And it worked fine!
Itâs just because a colleague said âWhat about migrations that add an index concurrentlyâ (like in GitHub - fly-apps/safe-ecto-migrations: Guide to Safe Ecto Migrations) that I switched to my current workaround. I just feared that such migrations could conflict with the table lock strategy, but I have to admit I didnât try it out.
We enabled the :pg_advisory_lock strategy for our elixir applications (like explained here and here) as a best practice, regardless whether they actually make use of concurrently creating indexes or not. We had not expected any downsides, but this assumption has now been proven wrong.
OK, I did a quick check: when a migration concurrently adds an index, using the :table_lock strategy does not work. The migration adds the index, but later operations (presumably inserting the migration version into the schema_migrations table) are deadlocked and the whole process hangs forever.
Sorry for the confusion. Weâre mixing up 2 aspects of the problem.
Does Phoenix.Ecto.CheckRepoStatus need to run under a migration lock? In most cases itâs a pure read operation (when there are no pending migrations). It would be great if the developers of phoenix_ecto and ecto_sql could change the code to not need a lock.
When there are migrations to run, Ecto needs a migration lock, thatâs out of question. Now which one is better? If you have migrations that concurrently add indexes, and if you do not want to completely disable the migration lock in the migration (@disable_migration_lock true) but instead choose to configure :pg_advisory_lock in config.exs (as advised in the âSafe Ecto Migrations guideâ), then you cannot opt out of that for the dev environment (by configuring :table_lock in dev.exs) anymore, that doesnât work.
I think what youâre running against is that checking if there are pending migrations already uses a lock. Iâd probably inquire in the ecto mailing list why this is the case and if it can be changed. The mailing list is the best way of getting a hold of the ecto maintainers. Looking at the latest changes to the API suggest there might be a good reason for how this currently works â even if not for the usecase the API is used within CheckRepoStatus.
Thanks that clears it up. So I believe you can already disable migrations locks by using migration_lock: false. If Iâm correct then maybe ecto_phoenix can be extended to allow that option to be passed into the plug. Then you can still use the option you want for your migrations in your config.
Oh, thatâs interesting. It didnât occur to me that you simply can turn off migration locking. It works! Just a minor drawback: a migration that concurrently adds an index prints out a warning in this scenario.
It would be great if the CheckRepoStatus plug used this option.