OneCDC is a docker container and a Python library, that provides 1C system data loading to data warehouse using Change Data Capture apporach.
It engages standard ODATA mechanism and standard 1C exchange plan mechanism to extract data from 1C system and upsert changes to the target DB.
OneCDC — это докер контейнер и python-библиотека, предназначенные для получения данных из 1С, использующий подход CDC (загрузка изменений данных).
Продукт использует стандартный интерфейс ODATA и механизм планов обмена для выгрузки изменений данных из системы 1С и обновления данных в целевой БД.
Общий принцип действия
- Основной объект библиотеки это оркестратор
Replicator, который циклично читает изменения из 1С (через OData + план обмена) и пишет их в целевую БД Postgres, подтверждая приём пакета только после успешного сохранения. - В Postgres объекты сохраняются в виде отдельных таблиц на каждый регистр, справочник, документ, табличные части документа или справочника. Структура соответствует структуре хранения в 1С, но имена таблиц и полей автоматически переводятся в транслит.
- Полученные таблицы вы можете сами использовать для построения запросов, но библиотека предлагает также механизм обработчиков (handlers). Когда из 1С приходят новые данные, обработчик обновляет соответствующую часть в витрине данных. Витрину вы описываете сами — представлением (view) в базе данных. В примере показано как сделать обновление витрины быстрым, только по изменениям. Также механизм обработчиков это по сути ваш код на python, в который вы можете вставить что нужно, например, отправка в RabbitMQ или еще что-то.
Что нужно для работы
- опубликовать базу 1с на web
- настроить план обмена в конфигураторе и включить в его состав нужные объекты 1с
- создать пользователя для доступа к odata и дать ему необходимые права (
чтениеиизменениек плану обмена,чтениек загружаемым объектам). - дать роль
чтениевсем пользователям к плану обмена (иначе будут ошибки при сохранении объектов) - создать узел обмена с использованием внешней обработки
onecdc.epf - запустить загрузку: докер-образом
sobolevp/onecdc(см. «Запуск в docker») либо python-библиотекойonecdc(см. ниже)
Использование библиотеки python
Установка
pip install onecdc
Для записи изменений необходим PostgreSQL (Другие СУБД не тестировались, хотя в теории возможны). Для записи используется библиотека dbmerge. Все необходимые схемы, таблицы и поля модуль создает сам.
from sqlalchemy import create_engine
from onecdc import Replicator
# pool_size >= full_load_workers + 3 (+1 на каждого обработчика и каждое расписание) —
# почему столько, см. README_DB.md, «Сколько нужно соединений к БД»
engine = create_engine("postgresql+psycopg2://user:pass@localhost:5432/onecdc", pool_size=5)
rep = Replicator(
odata_url="http://host/base/odata/standard.odata",
odata_auth=("odata", "secret"), # (user, password) либо None без авторизации
exchange_name="ВашПланОбмена", # имя плана обмена в 1С
queue_guid="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", # Ref_Key узла обмена
engine=engine,
db_schema="onecdc", # None → схема БД по умолчанию (public у Postgres)
db_temp_schema="onecdc_tmp", # схема промежуточных таблиц merge; None → схема данных
request_timeout=60, # таймаут HTTP-запросов к 1С, сек (по умолчанию 60 на коннект, 900 на ответ)
full_load_workers=2, # число фоновых потоков полной выгрузки
)
rep.run_forever(interval=60) # цикл опроса раз в 60 секунд
Вариант многопоточного запуска, дающий возможность добавления нескольких обработчиков (Handler) и дополнительных репликаторов (Replicator) для других планов обмена, можно посмотреть в этом файле: runner.py
Запуск в docker
docker run --rm --network host \
-e ONECDC_ODATA_URL="http://server/base/odata/standard.odata" \
-e ONECDC_ODATA_USER=odata -e ONECDC_ODATA_PASSWORD=secret \
-e ONECDC_EXCHANGE_NAME="ВашПланОбмена" \
-e ONECDC_QUEUE_GUID="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" \
-e ONECDC_DB_URL="postgresql+psycopg2://user:pass@database_host:5432/cdc" \
-e ONECDC_DB_SCHEMA=onecdc -e ONECDC_DB_TEMP_SCHEMA=onecdc_tmp \
-v "$PWD/config:/config:ro" \
sobolevp/onecdc:latest
-v "$PWD/config:/config:ro" — монтирует папку config из текущего каталога. В ней лежит файл runner.py, а также подпапка с примерами обработчиков (config/handlers).
docker compose. Пример — docker-compose.yml в репозитории.
Запуск из окружения
Если хочется не писать код вовсе, есть готовый entrypoint — python -m onecdc (он же команда
onecdc). Он читает те же параметры из переменных окружения, см описание: README_ENV.md
Как узнать guid узла обмена
queue_guid — это Ref_Key узла плана обмена, того самого, на который 1С регистрирует изменения
(ЭтотУзел не подходит: он описывает саму базу-источник). Если guid неизвестен, оставьте параметр
пустым (queue_guid="", или просто не задавайте ONECDC_QUEUE_GUID) и запустите: чтение изменений
выведет в лог список узлов плана обмена и остановится.
ERROR onecdc.change_reader: queue_guid is not set. Available nodes of exchange plan ДляODATA:
a9bc23c5-3689-11f1-926c-0800270bc6cb CDC Витрина
Guid из первой колонки и есть искомый queue_guid.
Режимы: run_once и run_forever
rep.run_once() # один цикл: read → save → notify (подтверждение только после save)
rep.run_forever(interval=60) # основной режим работы. бесконечный цикл run_once с паузой; фоном — полные выгрузки
run_once(notify_changes=False)— не подтверждать приём (пакет останется в очереди 1С; сделано для отладки).run_forever(interval, max_iterations=0)—max_iterations>0ограничивает число итераций.
Полная (первоначальная) выгрузка
При работе run_forever объекты, впервые встреченные в пакете изменений, автоматически ставятся в
очередь на полную выгрузку и грузятся фоновыми потоками.
- Можно запустить выгрузку и вручную, поставив флаг в таблице onecdc_metadata_objects - full_load_is_required=
True - Полная выгрузка спроектирована так, чтобы работать параллельно с получением изменений объекта и не затирать свежие изменения объекта. Также она автоматически разбивает объект на отрезки по времени и выгружает его порциями с автоматическим подбором размера (batch_size).
Что появляется в целевой БД
На каждый объект 1С заводится своя таблица: имя транслитерируется, к полям добавляются служебные
(merged_on, inserted_on, is_deleted_or_empty, exchange_message_no). Схемы, таблицы и новые
колонки библиотека создаёт сама. Рядом появляются служебные таблицы, по которым видно состояние
загрузки: журнал onecdc_replicator_log, реестр объектов onecdc_metadata_objects, состояние обработчиков
onecdc_handlers и реестр незавершённых записей onecdc_writes_in_process.
Подробно — README_DB.md: состав полей, что означает is_deleted_or_empty, зачем
отдельная схема промежуточных таблиц и что лежит в каждой служебной таблице.
Классы библиотеки
Replicator читает изменения и пишет их в БД, Handler + HandlerLoop дают возможность запуска своего кода
по событию изменения, FullLoadCron — полную выгрузку по расписанию. Что каждый из них принимает и
что у него можно вызвать — README_API.md.
Логирование
Из коробки библиотека вешает вывод на логгер onecdc (INFO), если приложение не настроило логирование
само. Настроили своё — библиотека молчит и пишет через стандартный logging.
Шум со стороны 1С
1С регистрирует изменение объекта на любую перезапись, поэтому в пакет приезжает масса записей, у которых поменялись только DataVersion и номер пакета. Такие записи библиотека изменением не считает: строка не обновляется, merged_on остаётся прежним — и обработчик, который выбирает данные по merged_on, впустую не запускается.
Дальнейшая обработка и материализация
1С хранит данные нормализованно: чтобы дотянуться из регистра до кода товара, нужен JOIN со
справочником по guid. Для КХД обычно удобнее менее строгая нормализация — витрины, собранные
заранее.
Считать их вхолостую по расписанию не нужно: репликатор знает, когда данные изменились, и сам вызывает ваш код. Такой код называется обработчиком — это класс с двумя строчками объявления:
from onecdc import Handler, HandlerContext
class ZakazyKlientov(Handler):
ON = ["AccumulationRegister_ZakazyKlientov"] # имена ТАБЛИЦ в БД, не объектов 1С
def handle(self, context: HandlerContext) -> None:
self.execute(context, "insert into ... where merged_on > :last_run_at",
last_run_at=context.last_run_at)
Тем же способом изменения отправляют во внешнюю систему — очередь, вебхук, другую БД.
Начинают обычно с представления (view): в нём собран SELECT со всеми JOIN по guid-ключам.
DDL можно прописать прямо в обработчике (setup) или завести отдельно. Дальше обработчик работает так:
- библиотека вызывает его, передавая дату и время
last_run_at— с них и нужно обновлять; - обработчик пишет
SELECT, который находит по представлению изменившиеся ключи условиемmerged_on > last_run_at(merged_onесть и у таблиц, подключённых черезJOIN, — см. пример); - этот
SELECTуходит в условия обновления dbmerge:source_conditionговорит, какие ключи взять из источника,delete_condition— в каком множестве ключей чистить строки, если что-то удалилось.delete_conditionнужен не всегда: строки, выпавшие из набора движений или табличной части, репликатор не удаляет, а помечает (см. «Шум со стороны 1С» иis_deleted_or_empty), поэтому витрине с тем же ключом, что у источника, достаточно обычного обновления. Удаление нужно там, где ключ витрины свой, — например, у агрегата поGROUP BY.
В примерах разобраны два варианта — с кодом и подробными пояснениями:
- ключ витрины совпадает с первичным ключом объекта 1С (суррогатный guid). Годится для таблицы фактов: config/handlers/zakazy_klientov.py;
- ключ витрины заменён на бизнес-ключ — например, номер документа вместо guid. Связь с «сырыми»
данными хранится в колонках-массивах (
ARRAY) с индексами GIN: по ним обработчик быстро находит, какие агрегированные ключи задело изменение в источнике. config/handlers/zakazy_klientov_grouped.py.
Ссылки
| файл | описание |
|---|---|
| README.md | этот файл: обзор, установка, запуск |
| README_ENV.md | запуск из окружения: все переменные ONECDC_*, значения по умолчанию, ошибки конфигурации |
| README_API.md | классы, которые собирает пользователь: Replicator, Handler, HandlerLoop, FullLoadCron; обработчики — окно изменений, когда их вызывают, пересборка витрины |
| README_DB.md | что появляется в целевой БД: таблицы, служебные поля, служебные таблицы |
| DESIGN.md | внутреннее устройство для тех, кто правит код: интерфейс OData, цикл изменений, пагинация полной выгрузки, гонки со снимком, механика обработчиков |
| CHANGELOG.md | что менялось от версии к версии |
| config/runner.py | шаблон точки входа: репликатор, обработчики и расписания в одном файле |
| config/handlers | примеры обработчиков |
Неофициальный проект, не связан с фирмой «1С». «1С» и «1С:Предприятие» — товарные знаки ООО «1С», используются для указания совместимости.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file onecdc-0.2.1.tar.gz.
File metadata
- Download URL: onecdc-0.2.1.tar.gz
- Upload date:
- Size: 772.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10e6bb21b826c62ca47ff4743131e1a4e7aea119a423342b29c08416376423b5
|
|
| MD5 |
1972df14be0cb7578e438e4f181f6810
|
|
| BLAKE2b-256 |
6e3e8fdc9e7e31238b2b16165bc287f4aa5bc9853200e9bf62563655027fd49a
|
File details
Details for the file onecdc-0.2.1-py3-none-any.whl.
File metadata
- Download URL: onecdc-0.2.1-py3-none-any.whl
- Upload date:
- Size: 148.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3df6b26d64c452eca8c9a6c5f01272f90cd5062f46ca371820b4bd753f6b768
|
|
| MD5 |
b4f0535659322677160d5edaaf698862
|
|
| BLAKE2b-256 |
77c557e49a07460a36831b5d432341479ccea3aab8ebc3be920b1517a490b9eb
|