TL;DR: Мы допустили ошибку при обновлении и ищем помощь
Мы используем Home Assistant и Discourse для работы нашего сообщества. Мы работаем с методом discourse_docker на экземпляре EC2 в AWS.
Как проект с открытым исходным кодом, обслуживание форума было упущено, и в итоге у нас осталась старая версия, которая последний раз обновлялась в начале 2019 года.
Чтобы усугубить ситуацию, при предыдущем обновлении мы зафиксировали версию Postgres на 9.5, так как у нас не было достаточно места на диске для перехода на Postgres 10. Мы так и не решили эту проблему.
Кроме того, мы однажды внесли изменения в шаблон Cloudflare и закоммитили их в репозиторий, что помешало ветке docker_discourse обновиться до последней версии.
Вчера мы решили провести обновление…
При миграции базы данных возникла проблема: использовался синтаксис, несовместимый с версией 9.5:
== 20200429095034 AddTopicThumbnailInformation: migrating =====================
-- execute("ALTER TABLE posts\nADD COLUMN IF NOT EXISTS image_upload_id bigint\n")
Мы быстро поняли проблему с фиксированной версией 9.5 и решили мигрировать на Postgres 10. Это не сработало, и мы получили ошибку:
I, [2020-06-12T00:30:55.448351 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 10
WARNING: Upgrading PostgresSQL would require an addtional 89M of disk space
Please free up some space, or expand your disk, before continuing.
У нас было доступно 47 ГБ, что казалось странным. Затем мы поняли, что discourse_docker устарел, и обновили его до последней версии. К нашему удивлению, только что вышла версия Postgres 12.
После повторного запуска rebuild на этот раз мы получили следующую ошибку:
I, [2020-06-12T00:41:17.378129 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 12
WARNING: Upgrading PostgresSQL would require an addtional 92G of disk space
Please free up some space, or expand your disk, before continuing.
Это уже немного больше места, но ладно. Давайте просто увеличим объем диска до 300 ГБ и попробуем снова.
На этот раз pg_upgrade прервался во время миграции:
Restoring database schemas in the new cluster
template1
discourse
*failure* Consult the last few lines of "pg_upgrade_dump_16384.log" for the probable cause of the failure. Failure, exiting
Когда мы посмотрели файл pg_upgrade_dump_16384.log, то увидели следующую ошибку:
pg_restore: creating VIEW "postgres_exporter.pg_stat_activity"
pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 721; 1259 678554 VIEW pg_stat_activity postgres
pg_restore: [archiver (db)] could not execute query: ERROR: column pg_stat_activity.waiting does not exist
LINE 27: "pg_stat_activity"."waiting",
^
Command was:
-- For binary upgrade, must preserve pg_type oid
SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('678556'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_type array oid
SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('678555'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_class oids
SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('678554'::pg_catalog.oid);
CREATE VIEW "postgres_exporter"."pg_stat_activity" AS
SELECT "pg_stat_activity"."datid",
"pg_stat_activity"."datname",
"pg_stat_activity"."pid",
"pg_stat_activity"."usesysid",
"pg_stat_activity"."usename",
"pg_stat_activity"."application_name",
"pg_stat_activity"."client_addr",
"pg_stat_activity"."client_hostname",
"pg_stat_activity"."client_port",
"pg_stat_activity"."backend_start",
"pg_stat_activity"."xact_start",
"pg_stat_activity"."query_start",
"pg_stat_activity"."state_change",
"pg_stat_activity"."waiting",
"pg_stat_activity"."state",
"pg_stat_activity"."backend_xid",
"pg_stat_activity"."backend_xmin",
"pg_stat_activity"."query"
FROM "pg_stat_activity";
О нет.
Тогда мы решили сделать несколько шагов назад. Могли бы мы просто запустить форум снова и перевести его в режим только для чтения, пока разбираемся с этой историей резервного копирования? Нам удалось это сделать, исправив некоторые проблемы с правами доступа для postgres и redis, и форум снова заработал на старой версии. Не всё работает, например, переход в админку → пользователи → группы вызывает эту ошибку:
NoMethodError (undefined method `automatic_membership_retroactive' for #<Group:0x00007fcaca3045e8>)
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
Но остальное, кажется, работает.
На этом этапе мы решили, что поскольку нам пришлось вручную менять владельца файлов, чтобы вернуть работающий экземпляр, лучше просто запустить новый экземпляр и импортировать нашу резервную копию.
Итак, мы запустили новый экземпляр EC2, выполнили инструкции по началу работы с discourse_docker и начали импорт. Затем мы столкнулись со странной проблемой: не удалось создать индекс, потому что данные не соответствовали требованиям уникальности индекса:
ERROR: could not create unique index "index_incoming_domains_on_name_and_https_and_port"
DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
EXCEPTION: psql failed: DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
/var/www/discourse/lib/backup_restore/database_restorer.rb:95:in `restore_dump'
Но когда мы зашли в консоль Rails нашего работающего экземпляра, дубликата не было:
[7] pry(main)> IncomingDomain.where(name: "homeassistant.home")
=> [#<IncomingDomain:0x000055e5cabc3760 id: 8648, name: "homeassistant.home", https: false, port: 8123>]
Вот где мы сейчас находимся. И мы немного потерялись.
- У нас есть работающий экземпляр с плохой БД по сравнению с Ruby-кодом, который не может мигрировать на новый Postgres.
- У нас есть резервная копия, которую нельзя импортировать в новый экземпляр.
Мы изучили возможность перехода на платный хостинг Discourse, но так как у нас 3 миллиона просмотров страниц и миллион сообщений, корпоративное ценообразование слишком обременительно для нас.
Поэтому нам нужно найти выход. В идеале мы хотели бы импортировать нашу резервную копию, но миграция старого экземпляра тоже подошла бы.
Есть ли у кого-нибудь идеи? Мы не против заплатить кому-то за помощь.