CDC

Подписка на потоки Change Data Capture из источников db.cdc.postgres и db.cdc.sqlite. Позволяет перечислить настроенные источники, открыть поток и получать события изменений на уровне строк через канал. API нейтрален к драйверу: оба вида возвращают одну и ту же информацию об источнике и одни и те же события изменений, различаясь только возможностями, которые они публикуют.

Загрузка

local cdc = require("cdc")

list_sources

Перечислить настроенные источники CDC, которые вызывающей стороне разрешено видеть:

local sources, err = cdc.list_sources()
for _, s in ipairs(sources) do
    print(s.id, s.kind, s.state, s.capabilities.before_images)
end

Источники, на которые у вызывающей стороны нет cdc.source, пропускаются, а не приводят к ошибке.

Возвращает: table, error

source

Получить один источник по имени (его ID записи):

local info, err = cdc.source("app:pg_cdc")
if info == nil then
    -- такого источника нет
end

Возвращает: table, error (информация об источнике либо nil, если не найден)

stream

Открыть поток изменений на источнике. Возвращает cdc.Stream, чей канал доставляет события изменений:

local stream, err = cdc.stream("app:pg_cdc", {
    tables = { "public.users", "public.orders" },
    ops    = { "insert", "update" },
    buffer = 128,
})
Параметр Тип По умолчанию Описание
name string обязателен Имя источника (ID записи)
opts.tables []string - Ограничить этими таблицами (опустите для всех захватываемых таблиц)
opts.ops []string - Ограничить этими операциями: insert, update, delete, truncate
opts.buffer int 64 Ёмкость очереди в элементах (1-65536)
opts.max_bytes int 1048576 Бюджет очереди в байтах для этого подписчика (1 МиБ)
opts.snapshot bool значение записи Запросить для этого потока снимок с переходом в живой режим
opts.after string - Непрозрачный курсор возобновления из поля cursor предыдущего события

Неизвестные ключи опций отклоняются с errors.INVALID. Имена таблиц сопоставляются без учёта регистра как с полным именем отношения, так и с голым именем таблицы. Строки снимка фильтруются только по tables; ops применяется к живым изменениям.

Поток получает снимок, если либо opts.snapshot равно true, либо в записи источника задано поле snapshot; строки снимка приходят первыми с op = "snapshot", затем поток без разрыва продолжается живыми изменениями. opts.after зарезервирован для драйверов, возобновляющих работу с курсора — все поставляемые сегодня драйверы возвращают на него errors.INVALID ("cdc operation is not supported by this source"), включая db.cdc.postgres, когда он сообщает о capture_resume.

Фильтры лишь сужают доставку. Доступ к источнику даёт разрешение cdc.subscribe, а не фильтр.

Возвращает: Stream, error

Методы Stream

channel

Вернуть канал, принимающий события изменений. Первый вызов оформляет подписку на источник (уступает управление); последующие вызовы возвращают тот же канал. :receive() блокируется до прихода следующего изменения либо возвращает nil, когда поток завершается:

local stream = cdc.stream("app:pg_cdc")
local ch = stream:channel()

while true do
    local change = ch:receive()
    if change == nil then break end   -- поток закрыт

    if change.op == "snapshot" then
        seed_row(change.table, change.after)
    elseif change.op == "insert" then
        handle_new_user(change.table, change.after)
    elseif change.op == "update" then
        handle_update(change.table, change.before, change.after)
    elseif change.op == "delete" then
        handle_delete(change.table, change.before)
    end
end

Поток ленивый: сначала создайте его, затем вызовите channel() до генерации записей, которые он должен наблюдать. Это живое наблюдение, а не воспроизведение изменений, сделанных до подписки.

Когда источник завершает поток с ошибкой, канал доставляет значение ошибки перед закрытием. receive — псевдоним для channel.

close

Остановить подписку и освободить поток. Идемпотентно; также закрывается автоматически по завершении задачи. release — псевдоним для close.

stream:close()

Событие изменения

Каждое сообщение, полученное в канале, — это таблица изменения:

Поле Описание
op Операция: insert, update, delete, snapshot или truncate
schema Схема таблицы
table Имя таблицы
relation Полное имя отношения
before Состояние строки до изменения (update, delete). Полный образ строки гарантирован, только когда источник имеет возможность before_images; db.cdc.postgres заполняет его тем старым кортежем, который несёт WAL, чем управляет REPLICA IDENTITY таблицы
after Состояние строки после изменения (insert, update, snapshot; отсутствует для delete)
source ID записи источника
source_id ID записи источника в виде ID реестра
generation Поколение источника, породившее событие
cursor Непрозрачная позиция события внутри источника
transaction Идентификатор транзакции, когда драйвер его сообщает
lsn Номер последовательности журнала для изменения (db.cdc.postgres)
commit_lsn LSN фиксирующей транзакции (когда применимо)
xid ID транзакции (когда применимо)
unchanged Колонки, значение которых не передавалось (неизменённые значения TOAST)
error Описание ошибки, сообщённое драйвером и переданное в событии

before и after — это отображения строки с ключами по именам колонок.

Информация об источнике

cdc.source и каждый элемент cdc.list_sources возвращают одну и ту же запись:

Поле Описание
id ID записи
kind db.cdc.postgres или db.cdc.sqlite
name Имя источника (ID записи)
state unknown, starting, running, faulted или stopped
generation Текущее поколение источника
epoch То же значение, что и generation
engine Имя движка, когда драйвер его сообщает
db_resource ID записи наблюдаемого SQL-ресурса (db.cdc.sqlite)
slot Имя слота репликации (db.cdc.postgres)
publication Публикация Postgres, когда настроена
tables Захватываемые таблицы, когда настроены
streaming db.cdc.sqlite: работает ли источник; db.cdc.postgres: настройка протокола streaming в записи
failover Режим слота отказоустойчивости (db.cdc.postgres)
temporary Временный слот (db.cdc.postgres)
snapshot Значение снимка по умолчанию на уровне записи
faulted Находится ли источник в состоянии faulted
error Последняя ошибка источника, если она записана
admission active, snapshots, reserved_bytes, rejected
capabilities snapshot, capture_resume, replayable, captures_external_writes, before_images, coalesced

Ветвитесь по capabilities, а не по kind:

local info = cdc.source("app:changes")
if not info.capabilities.before_images then
    -- before не гарантирует полный образ строки; храните собственное последнее известное состояние
end

Семантику полей см. в источниках CDC.

Разрешения

Действие Ресурс Описание
cdc.source ID записи источника cdc.source; также фильтрует cdc.list_sources
cdc.subscribe ID записи источника cdc.stream, проверяется повторно при установлении подписки

Запрещённое действие возвращает errors.PERMISSION_DENIED.

Ошибки

Условие Вид
Нет контекста errors.INTERNAL
Требуется имя источника errors.INVALID
Некорректная или неизвестная опция потока errors.INVALID
after на источнике без capture_resume errors.INVALID
Источник не зарегистрирован errors.NOT_FOUND
Источник не запущен или заменяется errors.UNAVAILABLE
Исчерпана ёмкость подписок errors.UNAVAILABLE
Доступ запрещён errors.PERMISSION_DENIED

О работе с ошибками см. Обработка ошибок.

См. также

  • Change Data Capture - Настройка источников и возможности
  • Channel - Семантика каналов
  • Database - Сервисы SQL-баз данных