Привет! Эта тема дает некоторый контекст о миграции, которую я медленно планирую и тестирую. В прошлую пятницу я наконец-то попробовал импортер Drupal на тестовом VPS, используя комбинацию этого и этого. Импортер все еще работает, пока я пишу это, поэтому я еще не смог протестировать функциональность тестового сайта, но он почти завершится.
Самая большая проблема, с которой я сталкиваюсь, — это ошибка «дублирующееся значение ключа» для 8 apparently случайных узлов (аналогов тем в Discourse) из примерно 80 000 узлов. Вот конкретные номера nid, на случай если здесь замешан какой-то очень странный баг, похожий на Y2K:
42081, 53125, 57807, 63932, 66756, 76561, 78250, 82707
Та же ошибка всегда возникает на этих же nid при повторном запуске импортера:
Traceback (most recent call last):
19: from script/import_scripts/drupal.rb:537:in `<main>'
18: from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
17: from script/import_scripts/drupal.rb:39:in `execute'
16: from script/import_scripts/drupal.rb:169:in `import_forum_topics'
15: from /var/www/discourse/script/import_scripts/base.rb:916:in `batches'
14: from /var/www/discourse/script/import_scripts/base.rb:916:in `loop'
13: from /var/www/discourse/script/import_scripts/base.rb:917:in `block in batches'
12: from script/import_scripts/drupal.rb:195:in `block in import_forum_topics'
11: from /var/www/discourse/script/import_scripts/base.rb:224:in `all_records_exist?'
10: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/transactions.rb:209:in `transaction'
9: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/database_statements.rb:316:in `transaction'
8: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'
7: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
6: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
5: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
4: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
3: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
2: from /var/www/discourse/script/import_scripts/base.rb:231:in `block in all_records_exist?'
1: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec': ERROR: duplicate key value violates unique constraint "import_ids_pkey" (PG::UniqueViolation)
DETAIL: Key (val)=(nid:42081) already exists.
20: from script/import_scripts/drupal.rb:537:in `<main>'
19: from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
18: from script/import_scripts/drupal.rb:39:in `execute'
17: from script/import_scripts/drupal.rb:169:in `import_forum_topics'
16: from /var/www/discourse/script/import_scripts/base.rb:916:in `batches'
15: from /var/www/discourse/script/import_scripts/base.rb:916:in `loop'
14: from /var/www/discourse/script/import_scripts/base.rb:917:in `block in batches'
13: from script/import_scripts/drupal.rb:195:in `block in import_forum_topics'
12: from /var/www/discourse/script/import_scripts/base.rb:224:in `all_records_exist?'
11: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/transactions.rb:209:in `transaction'
10: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/database_statements.rb:316:in `transaction'
9: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'
8: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
7: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
6: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
5: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
4: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
3: from /var/www/discourse/script/import_scripts/base.rb:243:in `block in all_records_exist?'
2: from /var/www/discourse/script/import_scripts/base.rb:243:in `ensure in block in all_records_exist?'
1: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec': ERROR: current transaction is aborted, commands ignored until end of transaction block (PG::InFailedSqlTransaction)
Единственный способ заставить его продолжить работу — это взломать условия SQL:
...
LEFT JOIN node_counter nc ON nc.nid = n.nid
WHERE n.type = 'forum'
AND n.status = 1
AND n.nid != 42081
AND n.nid != 53125
AND n.nid != 57807
AND n.nid != 63932
AND n.nid != 66756
AND n.nid != 76561
AND n.nid != 78250
AND n.nid != 82707
LIMIT #{BATCH_SIZE}
OFFSET #{offset};
...
Я проверил первый неудачный узел, а также предыдущий и следующий nid по обе стороны от него в исходной базе данных Drupal, но не нашел ничего неправильного. nid установлен как первичный ключ и имеет AUTO_INCREMENT, и исходный сайт Drupal работает нормально, поэтому не может быть никакой фундаментальной проблемы с целостностью исходной базы данных.
Помимо вышеупомянутого бага, вот ограничения, с которыми я сталкиваюсь в скрипте:
-
Постоянные ссылки: Похоже, что скрипт импортера создаст постоянные ссылки для бывших URL узлов
example.com/node/XXXXXXX. Но мне также нужно сохранить ссылки на конкретные комментарии внутри этих узлов, которые имеют формат:example.com/comment/YYYYYYY#comment-YYYYYYY(YYYYYYYодинаково в обоих случаях). Схема URL Drupal не включает ID узла, с которым связан комментарий, тогда как в Discourse он есть (example.com/t/topic-keywords/XXXXXXX/YY), так что это выглядит как серьезное осложнение. -
Ограничения имен пользователей: Drupal позволяет использовать пробелы в именах пользователей. Я понимаю, что Discourse не позволяет этого делать, по крайней мере, новые пользователи не могут создавать такие имена. Этот пост предполагает, что скрипт импортера автоматически «преобразует» проблемные имена пользователей, но я не вижу кода для этого вОбновление: На самом деле кажется, что Discourse обработал это автоматически правильным образом./import_scripts/drupal.rb. -
Заблокированные пользователи: Похоже, что скрипт импортирует всех пользователей, включая заблокированные учетные записи. Я мог бы довольно легко добавить условие в выборку SQL
WHERE status = 1, чтобы импортировать только активные учетные записи пользователей, но я не уверен, вызовет ли это проблемы с сериализацией записей. Прежде всего, я бы предпочел навсегда заблокировать ранее заблокированные имена учетных записей с их связанными адресами электронной почты, чтобы те же проблемные пользователи не могли зарегистрироваться снова в Discourse. -
Поля профиля пользователя: Знает ли кто-нибудь, есть ли пример кода в одном из других импортеров для импорта полей личной информации из профилей учетных записей пользователей? У меня есть только одно поле профиля («Местоположение»), которое нужно импортировать.
-
Аватары (не Gravatars): Казалось бы странно, что в импортере Drupal есть код для импорта Gravatars, но не для гораздо более часто используемых локальных изображений аватаров учетных записей.
-
Личные сообщения: Почти все форумы Drupal 7, вероятно, будут использовать сторонний модуль privatemsg (официальной функциональности PM в Drupal нет). Импортер не поддерживает импорт личных сообщений. В моем случае мне нужно импортировать около 1,5 млн из них.
Заранее спасибо за вашу помощь и за то, что сделали скрипт импортера Drupal доступным.




