NIFI-7180 Added CaptureChangeMongoDB - #11713
Open
danmorcov88 wants to merge 1 commit into
Open
danmorcov88 wants to merge 1 commit into
danmorcov88 wants to merge 1 commit into
Conversation
CaptureChangeMongoDB reads a MongoDB Change Stream for a collection or for a database and writes insert, update, replace, delete and invalidate events as records through a Record Writer, one FlowFile per batch. Documents are written as Extended JSON, so a collection without a fixed shape stays readable. The resume token is stored in cluster state in the same transaction as the FlowFiles of its batch, so the stored position can never run ahead of what was delivered and events are delivered at least once. The stream is opened with startAfter, which also carries on past the invalidate event the server sends when a collection is dropped or renamed. A position the server can no longer serve is reported and kept by default, or given up on purpose with On History Lost. Failed attempts are retried with a growing wait, up to a minute. An aggregation pipeline can be given and is applied by the server before the events are sent. Start Position chooses between the current moment, a point in time, and an initial snapshot that writes the documents the collection already holds and then carries on from the moment the snapshot was taken. The processor never writes to the source: it needs only the changeStream and find privileges on the watched scope. verify checks the connection, that the deployment is a replica set or a sharded cluster, the server version, the privileges, and the pre-image configuration when it is needed. MongoDB 6.0 or later is required. Covered by unit tests and by Testcontainers tests against MongoDB 7.0 and 8.0, including an assertion that the insert, update and delete counters of the server do not move while the processor runs.
danmorcov88
force-pushed
the
NIFI-7180
branch
from
September 23, 2026 05:57
f7535f7 to
ed6c563
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
NIFI-7180
Adds
CaptureChangeMongoDB, a source processor that reads a MongoDB change stream and writes the events asrecords. NiFi has CDC for MySQL but nothing for MongoDB, and the ticket has been open since 2020 without a
pull request. The usual answer today is Debezium or the MongoDB Kafka Connector plus Kafka between MongoDB
and NiFi, which is two extra systems for what one change stream cursor does on its own.
The bundle is laid out as
nifi-extension-bundles/nifi-cdc/nifi-cdc-mongodb-bundle, next to the MySQL one,and uses the existing
MongoDBClientService, so connection settings and credentials stay in one place.What it does
a database, and writes them through a Record Writer, one FlowFile per batch.
operation,database,collection,document_key,full_document,full_document_before_change,updated_fields,removed_fields,cluster_time,wall_time,txn_number,resume_token.events it drops never travel. Only the stages MongoDB allows on a change stream are accepted, and the
pipeline is checked while the processor is configured.
Start Positionchooses the current moment, a point in time, or an initial snapshot that writes thedocuments a collection already holds and then carries on from the moment the snapshot was taken.
Full Document,Full Document Before ChangeandExtended JSON Modemap onto the driver options.VerifiableProcessor: connection, replica set ormongos, server version, thechangeStreamand
findprivileges on the watched scope, and the pre-image configuration when it is asked for.Notes on the design
Documents are Extended JSON strings, not mapped record fields. A collection has no fixed shape, so a
schema per collection would either be wrong or would have to be inferred. Writing the document as Extended
JSON keeps every BSON type and lets a flow pick it apart with the record path processors when it wants to.
Extended JSON Modechooses between the relaxed and the canonical form.The resume token is stored with
session.setStateinside the session, not after the commit. The tokenand the FlowFiles of its batch are then part of the same transaction, so the stored position can never run
ahead of what was delivered. A failure replays the events after the last committed token and never steps
over them, which makes delivery at-least-once. Before the first commit there is no committed token, so the
position the cursor reports when it is opened is kept in memory and used instead; without that, a batch
that failed before the first commit would reopen the stream at "now" and skip exactly the events that
failed.
The stream is always opened with
startAfter, neverresumeAfter. The two behave the same for anordinary token, and only
startAfteraccepts the token of an invalidate event. That is what lets thestream carry on when the watched collection is dropped or renamed, without a second code path or a state
flag recording which of the two to use. It needs MongoDB 4.2 or later; the processor requires 6.0.
A position the server cannot serve is recognised in both forms.
ChangeStreamHistoryLost(286) is thedocumented one, but a server asked to resume from a token that is not in the oplog answers
ChangeStreamFatalError(280) with "cannot resume stream; the resume token was not found". Both count;other fatal stream errors keep the ordinary retry.
On History Lostdecides whether the flow stops with anerror and keeps the position, which is the default, or gives it up on purpose and restarts at the present.
An idle stream still stores progress. The server reports how far it has read even when it sends no
event, so a quiet collection does not keep an old position while the oplog moves on.
Deployment scope is not included. A change stream over a whole deployment needs
MongoClient.watch(),which the driver sends with
allChangesForCluster: true.MongoDBClientServicehands out aMongoDatabaseonly, andgetDatabase("admin").watch()is not the same thing, since the driver tags it atdatabase level and it reports changes to
adminalone. Collection and database scope are covered. If theproject is open to adding an accessor for the
MongoClienttoMongoDBClientService, the field alreadyexists on
MongoDBControllerServiceand deployment scope becomes a third branch; I am happy to raise thatas a separate Jira rather than widen this pull request.
The processor never writes to the source. It needs
changeStreamandfindon the watched scope andnothing else: no collection is created, no index is added, no
collModis run. Pre-images are turned on byan administrator. An integration test reads
serverStatus().opcountersbefore and after a run and fails ifthe insert, update or delete counters moved.
Dependencies.
mongodb-driver-syncandnifi-mongodb-client-service-apiareprovided; the NARdeclares
nifi-mongodb-client-service-api-naras its parent NAR, the same waynifi-mongodb-nardoes, soneither the driver nor the service API is bundled a second time. No new third-party dependency is
introduced.
Testing
Unit tests drive the processor with a fake cursor and a clock the test moves, covering the record mapping
for every operation type, the batch loop, the stored state, the pipeline validation, the behaviour after a
failed batch, the two forms of a lost position, and the growing wait between attempts.
Integration tests use Testcontainers against MongoDB 7.0 and 8.0 and cover: every operation in order;
changes made while the processor is stopped; a dropped collection and the stream carrying on past the
invalidate; a position the server rejects, with both settings of
On History Lost; a paused server and therecovery afterwards; a multi-document transaction sharing its
txn_number; database scope; a$matchpipeline filtering on the server;
Update Lookup; pre-images; canonical Extended JSON; a start position inthe past; that no write reaches the server; and an initial snapshot of fifty thousand documents with writes
made while it runs, where every document present at the start has to come out, plus a snapshot interrupted
after three batches that carries on and reads every document exactly once.
Tracking
Issue Tracking
Pull Request Tracking
NIFI-7180NIFI-7180Pull Request Formatting
mainbranchVerification
Please indicate the verification steps performed prior to pull request creation.
Build
./mvnw clean install -P contrib-checkRun for the new bundle and everything it depends on,
-pl nifi-extension-bundles/nifi-cdc/nifi-cdc-mongodb-bundle/nifi-cdc-mongodb-nar -am, 105 modules, on bothJDKs.
Licensing
LICENSEandNOTICEfilesNo third-party dependency is added to the project.
mongodb-driver-syncis already used bynifi-mongodb-bundleand is taken here with scopeprovidedat the version that bundle declares; itreaches the processor at runtime through
nifi-mongodb-client-service-api-nar, which the NAR declares asits parent NAR. Nothing new is bundled, so no
LICENSEorNOTICEentry is needed; the NAR carries aNOTICElikenifi-cdc-mysql-nar.Documentation
The processor documentation comes from the annotations. It was checked in a running NiFi 2.x: the processor
appears in the palette, and the property list, the allowable values, the dependent properties and the state
description render as intended.