PG::UndefinedTable: ERROR: отношение "voice_rooms" не существует

Продолжая обсуждение из Fatal: could not read Username for ‘https://github.com’:

Проблемы с GitHub, похоже, решены, но обновление всё равно не проходит. Вот первый инцидент:

rake aborted!
StandardError: An error has occurred, this and all later migrations canceled: (StandardError) 
PG::UndefinedTable: ERROR:  relation "voice_rooms" does not exist

Использую 2-контейнерную конфигурацию (я также выполнил data, ошибок не было) и нахожусь на последней версии.

Есть идеи?

Ошибка PG::UndefinedTable: ERROR: relation "voice_rooms" does not exist появляется, потому что миграции для нового встроенного плагина voice ещё не были выполнены.

Что было указано выше сообщения rake aborted!?

Там… много :laughing: Но ничего, что бы меня зацепило.

x86_64 arch detected.                                                                                                                                                 
Ensuring launcher is up to date                                                                                                                                       
Launcher is up-to-date                                                                                                                                                
Stopping old container                                                                                                                                                
+ /usr/bin/docker stop -t 600 web_only                                                                                                                                
web_only                                                                                                                                                              
2.0.20260812-0036: Pulling from discourse/base                                                                                                                        
Digest: sha256:837e8ed4b5916baa36856b842ad84fe262b6b1b5550701f8844b13cc7acad7a5                                                                                       
Status: Image is up to date for discourse/base:2.0.20260812-0036                                                                                                      
docker.io/discourse/base:2.0.20260812-0036                                                                                                                            
/usr/local/lib/ruby/gems/3.4.0/gems/pups-1.4.0/lib/pups.rb                                                                                                            
/usr/local/bin/pups --stdin                                                                                                                                           
I, [2026-09-03T08:55:23.418621 #1]  INFO -- : Reading from stdin                                                                                                      
I, [2026-09-03T08:55:23.453117 #1]  INFO -- : > thpoff echo "thpoff is installed!"                                                                                    
thpoff is installed!                                                                                                                                                  
I, [2026-09-03T08:55:23.461963 #1]  INFO -- : > /usr/local/bin/ruby -e 'if (ENV["DISCOURSE_SMTP_ADDRESS"] == "smtp.example.com" && ENV["DISCOURSE_SKIP_EMAIL_SETUP"] !
= "1"); puts "Aborting! Mail is not configured!"; exit 1; end'                                                                                                        
I, [2026-09-03T08:55:23.608522 #1]  INFO -- : > /usr/local/bin/ruby -e 'if ENV["DISCOURSE_HOSTNAME"] == "discourse.example.com"; puts "Aborting! Domain is not configu
red!"; exit 1; end'                                                                                                                                                   
I, [2026-09-03T08:55:23.743204 #1]  INFO -- : > /usr/local/bin/ruby -e 'if (ENV["DISCOURSE_CDN_URL"] || "")[0..1] == "//"; puts "Aborting! CDN must have a protocol sp
eified

Я подозреваю, что это может быть связано с тем, что версии миграций предыдущего плагина resenha совпадают с версиями миграций нового плагина voice — вероятно, потому что вы установили его раньше? Если вы не уверены, попробуйте выполнить этот запрос в psql:

  SELECT version, name, direction, created_at, git_version
  FROM schema_migration_details
  WHERE version = '20241107000000'
  ORDER BY created_at;

См. resenha/db/migrate/20241107000000_create_resenha_rooms.rb at b87ca4e20d649ba6b7bdc4615b289c414854889e · xfalcox/resenha · GitHub и discourse/plugins/voice/db/migrate/20241107000000_create_voice_rooms.rb at main · discourse/discourse · GitHub

В ядре должно быть исправление для этого конфликта версий миграций.. Я бы предположил, что это должно затрагивать и других. Следите за новостями.

Да, я пробовал его на раннем этапе, но позже убрал.

Хорошо — скорее всего, это миграция resenha, которая, как предполагалось, была выполнена, но на самом деле не выполнялась. Поскольку в core для голосовых функций используется тот же номер версии миграции, попытка добавить столбец для voice_rooms внезапно не сработает, потому что имя таблицы всё ещё остаётся resenha_rooms.

Пока что вы можете выполнить это в вашем psql:

DO
$$
  DECLARE
    has_resenha boolean;
    has_voice   boolean;
    table_pair  record;
  BEGIN
    SELECT EXISTS (SELECT 1
                   FROM unnest(ARRAY [
                     'resenha_rooms',
                     'resenha_room_memberships',
                     'resenha_sessions',
                     'resenha_co_presences',
                     'resenha_recordings',
                     'resenha_invites'
                     ]) AS names(name)
                   WHERE to_regclass(format('public.%I', name)) IS NOT NULL)
    INTO has_resenha;

    SELECT EXISTS (SELECT 1
                   FROM unnest(ARRAY [
                     'voice_rooms',
                     'voice_room_memberships',
                     'voice_sessions',
                     'voice_co_presences',
                     'voice_recordings',
                     'voice_invites'
                     ]) AS names(name)
                   WHERE to_regclass(format('public.%I', name)) IS NOT NULL)
    INTO has_voice;

    IF has_resenha AND has_voice THEN
      RAISE EXCEPTION
        'Both Resenha and Voice tables exist. Nothing was changed.';
    END IF;

    IF NOT has_resenha THEN
      IF to_regclass('public.voice_rooms') IS NOT NULL THEN
        RAISE NOTICE 'The tables have already been renamed.';
        RETURN;
      END IF;

      RAISE EXCEPTION
        'Neither resenha_rooms nor voice_rooms exists. Nothing was changed.';
    END IF;

    IF EXISTS (SELECT 1
               FROM schema_migrations
               WHERE version = '20260831162602') THEN
      RAISE EXCEPTION
        'The rename migration is already recorded. Nothing was changed.';
    END IF;

    FOR table_pair IN
      SELECT *
      FROM (VALUES ('resenha_rooms', 'voice_rooms', '20241107000000'),
                   ('resenha_room_memberships', 'voice_room_memberships',
                    '20241107000000'),
                   ('resenha_sessions', 'voice_sessions', '20260305165400'),
                   ('resenha_co_presences', 'voice_co_presences',
                    '20260305165401'),
                   ('resenha_recordings', 'voice_recordings', '20260717172530'),
                   ('resenha_invites', 'voice_invites',
                    '20260813160047')) AS pairs(old_name, new_name, migration_version)
      LOOP
        IF EXISTS (SELECT 1
                   FROM schema_migrations
                   WHERE version = table_pair.migration_version) AND
           to_regclass(format('public.%I', table_pair.old_name)) IS NULL THEN
          RAISE EXCEPTION
            'Migration % is recorded, but table % is missing. Nothing was changed.',
            table_pair.migration_version,
            table_pair.old_name;
        END IF;

        IF to_regclass(format('public.%I', table_pair.old_name)) IS NOT NULL THEN
          EXECUTE format(
            'ALTER TABLE public.%I RENAME TO %I',
            table_pair.old_name,
            table_pair.new_name
                  );

          RAISE NOTICE 'Renamed % to %', table_pair.old_name, table_pair.new_name;
        END IF;
      END LOOP;
  END
$$;

Скрипт выполняет следующее:

  1. Проверяет, какие таблицы Resenha и Voice существуют.
  2. Откажется продолжать, если обе существуют (я не ожидаю, что это произойдёт).
  3. Проверяет, что записанные миграции соответствуют ожидаемым.
  4. Переименовывает существующие таблицы:
    • resenha_rooms → voice_rooms
    • resenha_room_memberships → voice_room_memberships
    • resenha_sessions → voice_sessions
    • resenha_co_presences → voice_co_presences
    • resenha_recordings → voice_recordings
    • resenha_invites → voice_invites
  5. Это поможет решить проблему с тем странным промежуточным состоянием, в котором вы находитесь. Пересборка после этого должна пройти успешно.

Это должно позволить остальным вашим миграциям core завершиться успешно (самая последняя миграция core для голосовых функций, которая выполняет переименование, будет пропущена как noop).

Я проверю с нашей командой, стоит ли нам закоммитить это как rake-задачу.

Спасибо! Всё сработало идеально.