ATLAS-5336: Upgrade Kafka to 3.9.1; embedded notification broker uses KRaft (no ZooKeeper)#689
Merged
Merged
Conversation
… KRaft Bump kafka-clients and embedded test broker from 2.8.2 to 3.9.1 (Scala 2.13), replace ZooKeeper-based EmbeddedKafkaServer with KafkaClusterTestKit, and update docker dev Kafka image packaging to kafka_2.13-3.9.1.
Point readers to ATLAS-5190 for full Jackson unification via Jersey 2.x.
added 10 commits
July 6, 2026 15:03
It leaked to falcon-bridge via atlas-notification and caused Failsafe to select JUnit Platform, which then failed on transitive junit 3.8.1 from falcon-common during FalconHookIT discovery.
Kafka 3.9 TestUtils needs junit-jupiter-api at test runtime; keep it off the compile classpath so falcon-bridge Failsafe stays on TestNG. Align mockito and testng with other Atlas modules (test scope).
… tests. NotificationHookConsumerKafkaTest starts EmbeddedKafkaServer, which uses Kafka 3.9 TestUtils requiring JUnit Jupiter on the test classpath. Test-scoped deps from atlas-notification do not propagate to webapp.
Shut down the import executor in @AfterMethod and wait with CountDownLatch instead of Thread.sleep so Mockito state does not leak between tests.
Scope hive searches to largedb. entities from the imported test dataset instead of the shared @cl1 cluster suffix, and tolerate Stream Closed during AdminExportImportTestIT teardown when the embedded server stops.
Scope BasicSearchIT to default. entities from hive-db-50-tables.zip instead of the shared @cl1 suffix, skip scoping for fulltext and paginated searches, keep junit-jupiter on the notification compile classpath for embedded KRaft runtime, and pin Failsafe to TestNG after junit landed on the webapp test path.
Derive EXTERNAL and CONTROLLER listeners from atlas.kafka.bootstrap.servers so Jetty and Failsafe JVMs share the same broker port, fixing NotificationHookConsumerIT topic timeouts on CI.
… conflicts. HiveHookIT fails when Jersey serializes AtlasClassification because isPropagate() and getPropagate() both map to "propagate"; AtlasType.toJson() matches the entity fix.
SqoopHookIT fails with NoClassDefFoundError for StreamConstraintsException when jackson-databind 2.16 is paired with an older jackson-core from Hadoop/Hive.
…t v1. StormAtlasHookIT fails with NoSuchFieldError for READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE when jackson-databind 2.16 is mixed with an older databind from storm-core on the test classpath. Co-authored-by: Cursor <cursoragent@cursor.com>
Pinning Failsafe to TestNG for the Kafka upgrade requires testng on the module test classpath; the extractor only has a stub IT and no test deps yet.
sarathsubramanian
approved these changes
Jul 8, 2026
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
KafkaClusterTestKit.kafka_2.13-3.9.1.HiveHookIT,SqoopHookIT,StormAtlasHookIT).atlas-trino-extractorFailsafe on defaultmvn verify(TestNG classpath after global Failsafe pin).Motivation
BasicSearchIT(3 vs 6 entity counts) andAdminExportImportTestITteardown when ITs share embedded-server state.Changes
kafka.versionkafka.scala.binary.versionEmbeddedKafkaServerKafkaServerKafkaClusterTestKit(KRaft)atlas-kafkaimagekafka_2.12-*kafka_2.13-3.9.1bootstrap.serversset at runtimewebapp/pom.xml— why these dependencies were addedThis PR bumps root
jackson.versionfrom 2.12.7 → 2.16.2 (required by Kafka 3.9KafkaClusterTestKittest dependencies). That version flows intoatlas-intg, which declares:jackson-jaxrs-baseat${jackson.version}jackson-jaxrs-json-providerat${jackson.version}Atlas server REST still runs on Jersey 1.19 (JAX-RS 1.1 / JSR-311). After the Jackson bump, the rebuilt server WAR pulled in Jackson JAX-RS 2.16 transitively while Jersey and its JSON providers expect the older 2.12-era JAX-RS integration. In manual Docker testing this produced an inconsistent classpath — Atlas failed to serve REST reliably (
GET /api/atlas/admin/versiondid not return 200) even though the Kafka/embedded-broker changes were correct.Fix in
webapp/pom.xml:jackson-jaxrs-basejackson-jaxrs-json-providerJacksonJaxbJsonProviderused by Jersey for JSON request/response serialization on Atlas REST APIsjsr311-apijavax.ws.rs.*) required by Jersey 1.x JSON providersatlas-intgexclusions on the twojackson-jaxrs-*artifacts prevent the WAR from also loading the 2.16.2 transitive copies. Webapp now owns a single, known-good JAX-RS Jackson version for the server while the rest of the build can use Jackson 2.16.2 where Kafka requires it.This is intentionally not a Jersey upgrade — it decouples server-side JAX-RS Jackson (2.12.7) from the core Jackson bump (2.16.2) needed for Kafka 3.9.1.
CI fixes (Kafka upgrade fallout)
falcon-bridgeFailsafe picked JUnit Platform afterjunit-jupiter-apileaked ontoatlas-notificationcompile classpathtestnotification/pom.xmlKafkaNotificationTest/NotificationHookConsumerKafkaTestSurefireNoClassDefFoundError: org/junit/jupiter/api/Assertionsjunit-jupiter-apiwithtestscope for unit testsnotification/pom.xmlEmbeddedKafkaServer/ IT Jetty startupNoClassDefFoundError: org/junit/jupiter/api/Assertionsat runtimejunit-jupiter-apionnotificationcompile classpath —KafkaClusterTestKit.waitForReadyBrokers()calls Kafka test utilities that reference Jupiter inside the WARnotification/pom.xmljunit-jupiter-apilanded on webapp test classpathsurefire-testngtomaven-failsafe-plugin(same as Surefire) so webapp ITs stay on TestNGpom.xml,webapp/pom.xmlImportTaskListenerImplTest.testStartImportConsumer_Successfulflaky on JDK 17 CI (Mockito argument mismatch from async executor leaking between tests)@AfterMethod; useCountDownLatchinstead ofThread.sleepwebapp/.../ImportTaskListenerImplTest.javaBasicSearchITexpected 3 hive tables but got 6 whenAdminExportImportTestITran first (shared@cl1cluster suffix)default.qualified names fromhive-db-50-tables.zip; skip scoping for fulltext (query) and paginated (offset > 0) searcheswebapp/.../BasicSearchIT.javaAdminExportImportTestIT.teardownfailed withStream Closed/ClientHandlerExceptionwhen embedded Jetty stopped firstwebapp/.../AdminExportImportTestIT.javaNotificationHookConsumerIT(6 tests) failed withTopic ATLAS_HOOK not present in metadata after 60000 msatlas.kafka.bootstrap.servers(localhost:19027) so Jetty and Failsafe IT JVMs share the same brokernotification/.../EmbeddedKafkaServer.javaHiveHookIT(testAlterTableRename,testTraitsPreservedOnColumnRename) failed withJsonMappingException: Conflicting getter definitions for property "propagate"onAtlasClassificationAtlasType.toJson()before Jersey POST (same pattern as #690 entity create/update)client/client-v2/.../AtlasClientV2.javaSqoopHookITtimed out after 80s; root causeNoClassDefFoundError: StreamConstraintsExceptioninAtlasClient.getEntity()jackson-databind2.16 +jackson-core2.16 (test scope) on sqoop-bridge IT classpath — Hadoop/Hive/Sqoop transitive deps supply olderjackson-coreaddons/sqoop-bridge/pom.xmlStormAtlasHookIT.testAddEntitiesfailed withNoSuchFieldError: READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUEinAtlasClient.getEntity()jackson-databind2.16 on storm-bridge IT classpath (existingjackson-coretest dep retained) —storm-coresupplies olderjackson-databindaddons/storm-bridge/pom.xmlatlas-trino-extractorFailsafeNoClassDefFoundError: org.testng.ITestListenerafter ~76 min CI buildtestngon the module test classpath; extractor has only a stubTrinoExtractorITand no test deps — setskipITs=trueon default verify (live ITs planned in ATLAS-5338)addons/trino-extractor/pom.xmlSkipped downstream modules — Jackson fix not required
Modules skipped after
storm-bridgefailed in the reactor were reviewed; none need the same preemptive Jackson pin:trino-extractorTrinoExtractorITonly;skipITs=trueavoids Failsafe/TestNG classpath failure on default verify; full live-stack ITs in ATLAS-5338atlas-examples/sample-appclassification-updaterjackson-databind2.16index-repair-toolnotification-analyzerdistprofile copies Jackson 2.16 jarsdistribution/docsExtra fix applied during testing — KRaft listener configuration
The first
EmbeddedKafkaServerport-binding fix hung startup because KRaft needs both listeners:EXTERNAL://localhost:19027— client traffic (matchesbootstrap.servers)CONTROLLER://localhost:0— KRaft controller (ephemeral port)Using only
PLAINTEXT://localhost:19027removed the controller listener and caused the hang.Updated
EmbeddedKafkaServernow sets:How listener configuration is applied (no hard-coded strings)
Nothing passes those listener strings literally.
EmbeddedKafkaServerderives them at runtime from config:atlas.kafka.bootstrap.serversinatlas-application.properties(e.g.localhost:19027for webapp ITs,localhost:9027placeholder in distro/docker).EmbeddedKafkaServerconstructor loads theatlas.kafka.*subset viaApplicationProperties.getSubsetConfiguration().buildBrokerConfig()callstoExternalListenerAddress(bootstrap.servers)→EXTERNAL://localhost:19027, then sets:listeners=EXTERNAL://<host>:<port>,CONTROLLER://localhost:0advertised.listeners=EXTERNAL://<host>:<port>KafkaClusterTestKit.Builder.setConfigProp(); the testkit starts the KRaft broker with that config.KafkaNotification(and IT producers) connect using the samebootstrap.serversvalue from properties.atlas-application.propertiesatlas.kafka.bootstrap.serversEmbeddedKafkaServer.buildBrokerConfig()listeners/advertised.listenersKafkaClusterTestKitEXTERNALon the configured port;CONTROLLERon ephemeral portKafkaNotification,NotificationHookConsumerbootstrap.serversWhy this matters for ITs: webapp integration tests run in two JVMs — Jetty (Atlas server + hook consumer) and Failsafe (test producer). Both must reach the same broker on the same port. The old ZK embedded broker bound to the configured port; the first KRaft change used an ephemeral port, so Failsafe still pointed at
localhost:19027while Jetty's broker listened elsewhere.flowchart LR subgraph Jetty["Jetty JVM (port 31000)"] EKS[EmbeddedKafkaServer] Hook[NotificationHookConsumer] end subgraph Failsafe["Failsafe IT JVM"] IT[NotificationHookConsumerIT] KN[KafkaNotification producer] end EKS -->|"binds EXTERNAL on :19027"| Kafka[(Embedded KRaft broker)] Hook -->|consumes ATLAS_HOOK| Kafka KN -->|produces ATLAS_HOOK| Kafka IT --> KNIf
bootstrap.serversis empty, no fixed listeners are set andKafkaClusterTestKitpicks ephemeral ports (acceptable for same-JVM unit tests likeKafkaNotificationTest, which updateApplicationPropertiesafter startup).Affected files
Kafka upgrade (core)
pom.xmlkafka.version3.9.1, Scala 2.13, Jackson 2.16.2, Failsafesurefire-testngnotification/pom.xmlnotification/src/main/java/org/apache/atlas/kafka/EmbeddedKafkaServer.javaKafkaClusterTestKit; bindEXTERNALlistener tobootstrap.serversnotification/src/main/java/org/apache/atlas/kafka/KafkaNotification.javadistro/src/conf/atlas-application.propertiesdev-support/atlas-docker/Dockerfile.atlas-kafkakafka_2.13-3.9.1imagedev-support/atlas-docker/.envdev-support/atlas-docker/download-archives.shServer / client classpath (Jackson + Jersey)
webapp/pom.xmljackson-jaxrs-*2.12.7 for Jersey 1.19; remove webapp-scoped Jupiter leakclient/client-v2/src/main/java/org/apache/atlas/AtlasClientV2.javaAtlasType.toJson()for entity POST/PUT (#690) + classification POST/PUT (this PR)client/common/src/main/java/org/apache/atlas/AtlasBaseClient.javaBridge hook IT classpath
addons/sqoop-bridge/pom.xmljackson-databind+jackson-core2.16 forSqoopHookIT/AtlasClientv1addons/storm-bridge/pom.xmljackson-databind2.16 forStormAtlasHookIT/AtlasClientv1addons/trino-extractor/pom.xmlskipITs=trueon defaultmvn verify(stub IT; notestngtest dep)Webapp integration / unit tests
webapp/src/test/java/org/apache/atlas/web/integration/BasicSearchIT.javadefault.entities; fulltext/pagination exceptionswebapp/src/test/java/org/apache/atlas/web/resources/AdminExportImportTestIT.javawebapp/src/test/java/org/apache/atlas/notification/ImportTaskListenerImplTest.javawebapp/src/test/java/org/apache/atlas/examples/QuickStartIT.javawebapp/src/test/java/org/apache/atlas/examples/QuickStartV2IT.javaOther (merged from master)
.github/workflows/ci.ymlintg/src/main/java/org/apache/atlas/utils/AuthenticationUtil.javarepository/src/test/java/org/apache/atlas/glossary/GlossaryServiceTest.javadev-support/atlas-docker/docker-compose.atlas-hbase.ymldev-support/atlas-docker/scripts/atlas-hbase.shdashboard/package.jsondashboard/src/views/Lineage/atlas-lineage/package-lock.jsondashboard/src/views/Lineage/atlas-lineage/package.jsondashboard/src/views/Lineage/atlas-lineage/webpack.config.jsdashboard/src/views/Statistics/StackedAreaCharts.jsxTesting
Unit tests
KafkaNotificationTestnotificationmvn -pl notification -Dtest=KafkaNotificationTest testATLAS_HOOKNotificationHookConsumerKafkaTestwebappmvn -pl webapp -am -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -Dtest=NotificationHookConsumerKafkaTest -DskipEnunciate=true testImportTaskListenerImplTestwebappmvn -pl webapp -am -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -Dtest=ImportTaskListenerImplTest -DskipEnunciate=true testNotificationHookConsumerKafkaTestandImportTaskListenerImplTestwere run with-amsoatlas-server-apiand sibling modules match compile-time APIs.Integration tests (local)
BasicSearchIT+AdminExportImportTestITmvn -Pdist,embedded-solr-it -DskipEnunciate=true -DskipDocs=true -DskipUTs=true -pl notification,webapp -am -Dfailsafe.failIfNoSpecifiedTests=false verify -Dit.test=BasicSearchIT,AdminExportImportTestITNotificationHookConsumerITmvn -Pdist,embedded-solr-it -DskipEnunciate=true -DskipDocs=true -DskipUTs=true -pl notification,webapp -am -Dfailsafe.failIfNoSpecifiedTests=false verify -Dit.test=NotificationHookConsumerITHiveHookIT(classification methods)AtlasClientV2toJson()fixSqoopHookITsqoop-bridgeJackson classpath pinStormAtlasHookITstorm-bridgeJackson databind pinManual — embedded KRaft broker smoke test
Unit tests exercise
EmbeddedKafkaServerinside a short-lived Surefire JVM. A separate manual check verified the same path in the full Atlas server process (complete WAR classpath, normal Spring startup order, real graph store and Solr).Setup: Atlas server running in Docker with Postgres and Solr. External Kafka broker was not required — embedded mode runs the broker in-process.
Steps:
atlas.notification.embedded=trueinatlas-application.properties(placeholderatlas.kafka.bootstrap.servers=localhost:9027).GET /api/atlas/admin/versionuntil HTTP 200.EmbeddedKafkaServer.start(isEmbedded=true)Starting embedded KRaft kafka (log.dir=.../data/kafka/kafka)Embedded KRaft kafka server started at localhost:<ephemeral-port>atlas.kafka.bootstrap.serverswas rewritten at runtime to the live broker address (placeholder not used as-is).atlas.notification.embedded=falseand external bootstrap servers; restart Atlas.Result: PASS — KRaft broker started inside the real server JVM; Atlas REST returned 200; graph, Solr, Jersey, and notification stack all initialized.
Manual — external Kafka 3.9.1 (production-like path)
Verified Atlas with
atlas.notification.embedded=falseagainst an external Kafka 3.9.1 broker (kafka_2.13-3.9.1), using the rebuilt Atlas server image.CREATE TABLEvia Hive; Atlas REST search forhive_columnon new tableATLAS_HOOKATLAS_ENTITIESconsumption; tag mapping visible in Ranger AdminSELECTon classified column as allowed/denied usersOverall: PASS — full metadata path (Hive → external Kafka → Atlas →
ATLAS_ENTITIES→ TagSync → Ranger) and audit paths worked with Kafka 3.9.1.Notes
atlas.notification.embedded=falseand externalbootstrap.servers.junit-jupiter-apiis intentionally not on the webapp test classpath anymore; notification owns the compile-scoped dependency required by embedded KRaft startup.localhost:19027in test config; embedded KRaft bindsEXTERNALon that port so Jetty and Failsafe JVMs share the same broker.hive-bridge,storm-bridge,sqoop-bridge) that callAtlasClientv1 via REST may need explicit Jackson 2.16 pins when Hadoop/Hive/Storm transitive deps supply older Jackson jars.atlas-trino-extractorskips Failsafe ITs on default CImvn verify; opt-in live-stack tests will use-Ptrino-extractor-itin ATLAS-5338.https://issues.apache.org/jira/browse/ATLAS-5336