Files
atc-agents/infra/airflow/scripts/cdc_emit.py
T

67 lines
2.0 KiB
Python

"""Lightweight change-event emitter to Kafka for sources without a native
Debezium connector (Cassandra 4.1 with cdc disabled, Neo4j 4.4 Community).
This performs an application-level dual-write: as the generators insert data,
each new record is also published to Kafka as a Debezium-style change event.
The platform's all-topics S3 consumer then archives these to object storage,
so Cassandra/Neo4j changes flow DB -> Kafka -> S3 just like the CDC sources.
Best-effort: never raises, so data generation cannot be broken by Kafka issues.
"""
import json
import os
import time
KAFKA_BOOTSTRAP = os.getenv("CDC_KAFKA_BOOTSTRAP", "10.0.21.36:9092")
_producer = None
def _default(o):
# make datetimes / uuids / Decimals JSON-serializable
try:
import datetime
if isinstance(o, (datetime.datetime, datetime.date)):
return o.isoformat()
except Exception:
pass
return str(o)
def _get_producer():
global _producer
if _producer is None:
from kafka import KafkaProducer
_producer = KafkaProducer(
bootstrap_servers=KAFKA_BOOTSTRAP,
value_serializer=lambda v: json.dumps(v, default=_default).encode("utf-8"),
linger_ms=50,
acks=1,
retries=3,
request_timeout_ms=20000,
)
return _producer
def emit_changes(topic, db, table, records):
"""Publish a list of dict records as change events. Returns count sent."""
if not records:
return 0
try:
p = _get_producer()
now = int(time.time() * 1000)
for r in records:
evt = {
"op": "c",
"ts_ms": now,
"source": {"connector": "app-cdc", "db": db, "table": table},
"after": r,
}
p.send(topic, evt)
p.flush(timeout=30)
print(f"[cdc] emitted {len(records)} change events -> {topic}")
return len(records)
except Exception as e:
print(f"[cdc] emit warning ({topic}): {str(e)[:200]}")
return 0