Refactor event ingestion into conversion + pipeline queues with MySQL source support - #21
Refactor event ingestion into conversion + pipeline queues with MySQL source support#21gengdy1545 wants to merge 8 commits into
Conversation
| public static RecordType classify(SourceRecord sourceRecord, String transactionTopic) | ||
| { | ||
| if (sourceRecord == null || sourceRecord.value() == null) | ||
| { | ||
| return RecordType.TOMBSTONE; | ||
| } | ||
| if (!(sourceRecord.value() instanceof Struct value)) | ||
| { | ||
| return RecordType.UNKNOWN_CONTROL; | ||
| } | ||
|
|
||
| if (transactionTopic != null && transactionTopic.equals(sourceRecord.topic())) | ||
| { | ||
| String status = DebeziumRecordUtil.getStringSafely(value, "status"); | ||
| String id = DebeziumRecordUtil.getStringSafely(value, "id"); | ||
| return (status.equals("BEGIN") || status.equals("END")) && !id.isBlank() | ||
| ? RecordType.TRANSACTION | ||
| : RecordType.UNKNOWN_CONTROL; | ||
| } | ||
|
|
||
| return isRowChange(value) ? RecordType.ROW : RecordType.UNKNOWN_CONTROL; | ||
| } | ||
|
|
||
| private static boolean isRowChange(Struct value) | ||
| { | ||
| String op = DebeziumRecordUtil.getStringSafely(value, "op").toLowerCase(Locale.ROOT); | ||
| if (!(op.equals("c") || op.equals("u") || op.equals("d") || op.equals("r"))) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| Object sourceObject = DebeziumRecordUtil.getFieldSafely(value, "source"); | ||
| if (!(sourceObject instanceof Struct source) || | ||
| DebeziumRecordUtil.getStringSafely(source, "db").isBlank() || | ||
| DebeziumRecordUtil.getStringSafely(source, "table").isBlank()) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| Object before = DebeziumRecordUtil.getFieldSafely(value, "before"); | ||
| Object after = DebeziumRecordUtil.getFieldSafely(value, "after"); | ||
| return switch (op) | ||
| { | ||
| case "c", "r" -> after instanceof Struct; | ||
| case "u" -> before instanceof Struct && after instanceof Struct; | ||
| case "d" -> before instanceof Struct; | ||
| default -> false; | ||
| }; | ||
| } | ||
|
|
||
| private void logSourceRecord(SourceRecord record, RecordType recordType) | ||
| { | ||
| if (!LOGGER.isDebugEnabled()) | ||
| { | ||
| return; | ||
| } | ||
| Struct value = record.value() instanceof Struct struct ? struct : null; | ||
| Struct source = value == null ? null : | ||
| asStruct(DebeziumRecordUtil.getFieldSafely(value, "source")); | ||
| Struct transaction = value == null ? null : | ||
| asStruct(DebeziumRecordUtil.getFieldSafely(value, "transaction")); | ||
| String rawTransactionId = recordType == RecordType.TRANSACTION | ||
| ? DebeziumRecordUtil.getStringSafely(value, "id") | ||
| : DebeziumRecordUtil.getStringSafely(transaction, "id"); | ||
| String canonicalTransactionId = | ||
| connectorAdapter.normalizeTransactionId(rawTransactionId); | ||
|
|
||
| LOGGER.debug("Debezium SourceRecord topic={}, sourcePartition={}, sourceOffset={}, " + | ||
| "keySchema={}, key={}, valueSchema={}, category={}, transaction.id={}, " + | ||
| "source.gtid={}, source.file={}, source.pos={}, source.row={}", | ||
| record.topic(), record.sourcePartition(), record.sourceOffset(), | ||
| schemaName(record.keySchema()), record.key(), schemaName(record.valueSchema()), | ||
| recordType, canonicalTransactionId, | ||
| DebeziumRecordUtil.getStringSafely(source, "gtid"), | ||
| DebeziumRecordUtil.getStringSafely(source, "file"), | ||
| DebeziumRecordUtil.getStringSafely(source, "pos"), | ||
| DebeziumRecordUtil.getStringSafely(source, "row")); | ||
| } | ||
|
|
||
| private static Struct asStruct(Object value) | ||
| { | ||
| return value instanceof Struct struct ? struct : null; | ||
| } | ||
|
|
||
| private static String schemaName(org.apache.kafka.connect.data.Schema schema) |
| return (dateToString); | ||
| } | ||
|
|
||
| public static String convertTimestampToString(Date date) |
There was a problem hiding this comment.
连MySQL和PG确认下CDC能不能正确解析。我记得Debezium Date、Time、Timestamp,包括不同精度的时间,有点复杂。
|
还有测试一下Decimal的解析 |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aa78cf9286
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| tablePipelineManager.close(); | ||
| transactionPipeline.close(); |
There was a problem hiding this comment.
Drain pipeline queues before closing storage playback
When sink.datasource=storage runs without looping, clean() waits only for the file-consumer threads, which merely enqueue converted records into the new table and transaction pipelines. These calls then close queues that explicitly discard pending values, so any backlog not yet written when file playback finishes is silently lost; wait for the pipeline processors to drain before closing them.
Useful? React with 👍 / 👎.
| if (adapter == null) | ||
| { | ||
| throw new IllegalStateException( | ||
| "No Debezium source adapter configured for " + topic); |
There was a problem hiding this comment.
Configure the adapter before decoding transaction metadata
With the packaged Kafka configuration (src/main/resources/pixels-sink.properties), debezium.connector.class is absent while this JSON transaction deserializer now requires an adapter. The first transaction record therefore throws here, and KafkaTransactionSource catches that exception outside its polling loop and terminates permanently, preventing transactional rows from being committed. Either supply/infer the adapter for Kafka transaction messages or reject the incomplete configuration at startup.
Useful? React with 👍 / 👎.
Summary
RowChangeEvent/TransactionMetadatainto pipeline queues.BlockingBoundedQueuefor backpressure and ordered delivery.Changes
Source conversion & pipelines
conversion(JSON/Avro/Struct converters, envelope normalizer, source adapters).TablePipeline/TransactionPipeline/TablePipelineManagerso processors consume canonical events only.KafkaRowSource/KafkaTransactionSourceand reworkPixelsDebeziumConsumerto convert at the source boundary.conf/pixels-sink.mysql.properties.Provider removal
EventProviderand per-source provider subclasses.BlockingBoundedQueuefor bounded, blocking handoff between sources and processors.overview,usage,configuration) to match the new architecture.Logging
pom.xml.log4j2.properties/jvm.confand drop unusedlogging.properties.