27
.github/workflows/deploy-docs-antora.yml
vendored
Normal file
27
.github/workflows/deploy-docs-antora.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Deploy Docs
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [ gh-pages ]
|
||||
tags: '**'
|
||||
workflow_dispatch:
|
||||
permissions: read-all
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'spring-projects'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: docs-build
|
||||
fetch-depth: 1
|
||||
- name: Dispatch (partial build)
|
||||
if: github.ref_type == 'branch'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
run: gh workflow run deploy-docs-antora.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
|
||||
- name: Dispatch (full build)
|
||||
if: github.ref_type == 'tag'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
||||
run: gh workflow run deploy-docs-antora.yml -r $(git rev-parse --abbrev-ref HEAD)
|
||||
@@ -6,7 +6,7 @@ Spring for Apache Pulsar provides a basic Spring-friendly API for developing htt
|
||||
|
||||
**#TIP#**: Most of the ideas in this project are borrowed from the Spring for Apache Kafka project, thus a familiarity with it would help.
|
||||
|
||||
include::spring-pulsar-docs/src/main/asciidoc/project-state.adoc[leveloffset=+1]
|
||||
include::spring-pulsar-docs/src/main/antora/modules/ROOT/pages/intro/project-state.adoc[leveloffset=+1]
|
||||
|
||||
== Getting Started
|
||||
The {docs}/html/[reference documentation] includes a {docs}/html/#quick-tourhtml[quick tour] section.
|
||||
|
||||
@@ -35,6 +35,8 @@ nohttp {
|
||||
source.exclude "**/out/**"
|
||||
source.exclude "**/target/**"
|
||||
source.exclude "**/*.dylib"
|
||||
source.exclude "**/*.gif"
|
||||
source.exclude "**/.gradle/**"
|
||||
}
|
||||
|
||||
check {
|
||||
|
||||
41
gradle/antora-docs.gradle
Normal file
41
gradle/antora-docs.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
node {
|
||||
version = '16.16.0'
|
||||
}
|
||||
|
||||
antora {
|
||||
version = '3.2.0-alpha.2'
|
||||
playbook = file('src/main/antora/antora-playbook.yml')
|
||||
options = ['to-dir' : project.layout.buildDirectory.dir('site').get().toString(), clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
|
||||
dependencies = [
|
||||
'@antora/atlas-extension': '1.0.0-alpha.1',
|
||||
'@antora/collector-extension': '1.0.0-alpha.3',
|
||||
'@asciidoctor/tabs': '1.0.0-beta.3',
|
||||
'@springio/antora-extensions': '1.4.2',
|
||||
'@springio/asciidoctor-extensions': '1.0.0-alpha.8',
|
||||
]
|
||||
}
|
||||
|
||||
tasks.named("generateAntoraYml") {
|
||||
asciidocAttributes = project.provider( { generateAttributes() } )
|
||||
baseAntoraYmlFile = file('src/main/antora/antora.yml')
|
||||
}
|
||||
|
||||
tasks.create(name: 'createAntoraPartials', type: Sync) {
|
||||
from { project(":spring-pulsar-docs").tasks.generateObservabilityDocs.outputs }
|
||||
into layout.buildDirectory.dir('generated-antora-resources/modules/ROOT/partials')
|
||||
}
|
||||
|
||||
tasks.create('generateAntoraResources') {
|
||||
dependsOn 'createAntoraPartials'
|
||||
dependsOn 'generateAntoraYml'
|
||||
}
|
||||
|
||||
def generateAttributes() {
|
||||
return ['spring-boot-version': project.springBootVersion ?: 'current',
|
||||
'spring-framework-version': project.springFrameworkVersion ?: 'current',
|
||||
'spring-cloud-stream-version': project.springCloudStreamVersion ?: 'current',
|
||||
'spring-pulsar-version': project.version,
|
||||
'pulsar-client-version': project.pulsarClientVersion ?: 'current',
|
||||
'pulsar-client-reactive-version': project.pulsarClientReactiveVersion ?: 'current',
|
||||
'is-snapshot-version': project.version.endsWith("-SNAPSHOT")]
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
plugins {
|
||||
id 'org.springframework.pulsar.spring-docs-module'
|
||||
id 'org.asciidoctor.jvm.convert'
|
||||
id 'org.springframework.pulsar.spring-module'
|
||||
id 'org.antora' version '1.0.0'
|
||||
id 'io.spring.antora.generate-antora-yml' version '0.0.1'
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/gradle/antora-docs.gradle"
|
||||
|
||||
description = 'Spring for Apache Pulsar Docs'
|
||||
|
||||
ext {
|
||||
@@ -77,96 +80,17 @@ task generateObservabilityDocs(type: JavaExec) {
|
||||
args observationsInputDir, /.+/, observationsOutputDir
|
||||
}
|
||||
|
||||
tasks.withType(org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask) {
|
||||
asciidoctorj {
|
||||
fatalWarnings = ['^((?!successfully validated).)*$']
|
||||
}
|
||||
forkOptions {
|
||||
jvmArgs "--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED"
|
||||
}
|
||||
doFirst {
|
||||
attributes "spring-boot-version": project.springBootVersion ?: 'current',
|
||||
"spring-framework-version": project.springFrameworkVersion ?: 'current',
|
||||
"spring-cloud-stream-version": project.springCloudStreamVersion ?: 'current',
|
||||
"spring-pulsar-version": project.version,
|
||||
"pulsar-client-version": project.pulsarClientVersion ?: 'current',
|
||||
"pulsar-client-reactive-version": project.pulsarClientReactiveVersion ?: 'current',
|
||||
"is-snapshot-version": project.version.endsWith("-SNAPSHOT")
|
||||
}
|
||||
}
|
||||
|
||||
asciidoctor {
|
||||
sources {
|
||||
include "*.singleadoc"
|
||||
}
|
||||
}
|
||||
|
||||
task asciidoctorPdf(type: org.asciidoctor.gradle.jvm.AsciidoctorTask) {
|
||||
sources {
|
||||
include "*.adoc"
|
||||
}
|
||||
}
|
||||
|
||||
task asciidoctorMultipage(type: org.asciidoctor.gradle.jvm.AsciidoctorTask) {
|
||||
sources {
|
||||
include "*.adoc"
|
||||
}
|
||||
}
|
||||
|
||||
syncDocumentationSourceForAsciidoctor {
|
||||
dependsOn generateObservabilityDocs
|
||||
from("${buildDir}/docs/generated") {
|
||||
into "asciidoc"
|
||||
}
|
||||
from("src/main/java") {
|
||||
into "main/java"
|
||||
}
|
||||
}
|
||||
|
||||
syncDocumentationSourceForAsciidoctorMultipage {
|
||||
dependsOn generateObservabilityDocs
|
||||
from("${buildDir}/docs/generated") {
|
||||
into "asciidoc"
|
||||
}
|
||||
from("src/main/java") {
|
||||
into "main/java"
|
||||
}
|
||||
}
|
||||
|
||||
syncDocumentationSourceForAsciidoctorPdf {
|
||||
dependsOn generateObservabilityDocs
|
||||
from("${buildDir}/docs/generated") {
|
||||
into "asciidoc"
|
||||
}
|
||||
from("src/main/java") {
|
||||
into "main/java"
|
||||
}
|
||||
}
|
||||
|
||||
task asciidocs {
|
||||
dependsOn asciidoctor, asciidoctorMultipage, asciidoctorPdf
|
||||
}
|
||||
|
||||
task docsZip(type: Zip) {
|
||||
dependsOn asciidocs
|
||||
task docsZip(type: Zip, dependsOn: [':spring-pulsar-docs:antora']) {
|
||||
group = 'Distribution'
|
||||
archiveClassifier = 'docs'
|
||||
description = "Builds docs archive containing api and reference for deployment at static.spring.io/spring-pulsar/docs."
|
||||
duplicatesStrategy "fail"
|
||||
from(asciidoctor.outputDir) {
|
||||
into "reference/htmlsingle"
|
||||
}
|
||||
from(asciidoctorPdf.outputDir) {
|
||||
into "reference/pdf"
|
||||
include "index.pdf"
|
||||
rename { "spring-pulsar-reference.pdf" }
|
||||
}
|
||||
from(asciidoctorMultipage.outputDir) {
|
||||
into "reference/html"
|
||||
}
|
||||
from(aggregatedJavadoc) {
|
||||
into "api"
|
||||
}
|
||||
from ('build/site') {
|
||||
into 'reference/'
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
|
||||
46
spring-pulsar-docs/src/main/antora/antora-playbook.yml
Normal file
46
spring-pulsar-docs/src/main/antora/antora-playbook.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
antora:
|
||||
extensions:
|
||||
- '@springio/antora-extensions/partial-build-extension'
|
||||
- require: '@springio/antora-extensions/latest-version-extension'
|
||||
- require: '@springio/antora-extensions/inject-collector-cache-config-extension'
|
||||
- '@antora/collector-extension'
|
||||
- '@antora/atlas-extension'
|
||||
- require: '@springio/antora-extensions/root-component-extension'
|
||||
root_component_name: 'pulsar'
|
||||
|
||||
site:
|
||||
title: Spring Pulsar
|
||||
url: https://docs.spring.io/spring-pulsar/reference/
|
||||
|
||||
content:
|
||||
sources:
|
||||
- url: ./../../../../
|
||||
branches: HEAD
|
||||
start_path: spring-pulsar-docs/src/main/antora
|
||||
worktrees: true
|
||||
|
||||
asciidoc:
|
||||
attributes:
|
||||
page-stackoverflow-url: https://stackoverflow.com/tags/spring-pulsar
|
||||
page-pagination: ''
|
||||
hide-uri-scheme: '@'
|
||||
tabs-sync-option: '@'
|
||||
chomp: 'all'
|
||||
listener-class: PulsarListener@
|
||||
template-class: PulsarTemplate@
|
||||
extensions:
|
||||
- '@asciidoctor/tabs'
|
||||
- '@springio/asciidoctor-extensions'
|
||||
sourcemap: true
|
||||
|
||||
urls:
|
||||
latest_version_segment: ''
|
||||
|
||||
runtime:
|
||||
log:
|
||||
failure_level: warn
|
||||
format: pretty
|
||||
|
||||
ui:
|
||||
bundle:
|
||||
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.3.5/ui-bundle.zip
|
||||
12
spring-pulsar-docs/src/main/antora/antora.yml
Normal file
12
spring-pulsar-docs/src/main/antora/antora.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
name: pulsar
|
||||
version: true
|
||||
title: Spring for Apache Pulsar
|
||||
nav:
|
||||
- modules/ROOT/nav.adoc
|
||||
ext:
|
||||
collector:
|
||||
run:
|
||||
command: gradlew :spring-pulsar-docs:generateAntoraResources
|
||||
local: true
|
||||
scan:
|
||||
dir: spring-pulsar-docs/build/generated-antora-resources
|
||||
19
spring-pulsar-docs/src/main/antora/modules/ROOT/nav.adoc
Normal file
19
spring-pulsar-docs/src/main/antora/modules/ROOT/nav.adoc
Normal file
@@ -0,0 +1,19 @@
|
||||
* xref:index.adoc[Overview]
|
||||
* xref:intro.adoc[Introduction]
|
||||
** xref:intro/project-state.adoc[Project Status]
|
||||
** xref:intro/system-requirements.adoc[System Requirements]
|
||||
** xref:intro/building.adoc[Building the Project]
|
||||
** xref:intro/getting-help.adoc[Getting Help]
|
||||
* xref:reference/reference.adoc[]
|
||||
** xref:reference/pulsar.adoc[]
|
||||
** xref:reference/reactive-pulsar.adoc[]
|
||||
** xref:reference/pulsar-admin.adoc[]
|
||||
** xref:reference/pulsar-function.adoc[]
|
||||
** xref:reference/observability.adoc[]
|
||||
** xref:reference/pulsar-binder.adoc[]
|
||||
* xref:other-resources.adoc[]
|
||||
* Appendices
|
||||
** xref:appendix/version-compatibility.adoc[]
|
||||
** xref:appendix/override-boot-dependencies.adoc[]
|
||||
** xref:appendix/non-ga-versions.adoc[]
|
||||
** xref:appendix/native-image.adoc[]
|
||||
@@ -1,8 +1,7 @@
|
||||
[appendix]
|
||||
[[appendix.native-images]]
|
||||
[[native-images]]
|
||||
= GraalVM Native Image Support
|
||||
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
https://www.graalvm.org/native-image/[GraalVM Native Images] are standalone executables that can be generated by processing compiled Java applications ahead-of-time. Native Images generally have a smaller memory footprint and start faster than their JVM counterparts.
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
[appendix]
|
||||
[[appendix.non-ga-versions]]
|
||||
[[non-ga-versions]]
|
||||
= Non-GA Versions
|
||||
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
You can find snapshot or milestone versions of the dependencies in the following repositories:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<repositories>
|
||||
<repository>
|
||||
@@ -37,8 +39,9 @@ You can find snapshot or milestone versions of the dependencies in the following
|
||||
</repositories>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
repositories {
|
||||
maven {
|
||||
@@ -55,3 +58,4 @@ repositories {
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
@@ -1,5 +1,4 @@
|
||||
[appendix]
|
||||
[[appendix.override-boot-deps]]
|
||||
[[override-boot-deps]]
|
||||
= Override Spring Boot Dependencies
|
||||
|
||||
When using Spring for Apache Pulsar in a Spring Boot application, the Apache Pulsar dependency versions are determined by Spring Boot's dependency management.
|
||||
@@ -9,7 +8,6 @@ Or, to use a different Spring for Apache Pulsar version with a supported Spring
|
||||
|
||||
In the following example, snapshot version of the Pulsar clients and Spring for Apache Pulsar are being used.
|
||||
|
||||
====
|
||||
[source, groovy, subs="+attributes", role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
@@ -22,8 +20,11 @@ dependencies {
|
||||
}
|
||||
----
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source, xml, subs="+attributes", role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<properties>
|
||||
<pulsar.version>3.1.1-SNAPSHOT</pulsar.version>
|
||||
@@ -36,5 +37,5 @@ dependencies {
|
||||
<artifactId>spring-boot-starter-pulsar-reactive</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
======
|
||||
|
||||
====
|
||||
@@ -1,8 +1,7 @@
|
||||
[appendix]
|
||||
[[appendix.version-compatibility]]
|
||||
[[version-compatibility]]
|
||||
= Pulsar Clients and Spring Boot Compatibility
|
||||
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
The following is the compatibility matrix:
|
||||
|===
|
||||
@@ -0,0 +1,12 @@
|
||||
[[overview]]
|
||||
= Overview
|
||||
include::attributes/attributes.adoc[]
|
||||
|
||||
include::overview/authors.adoc[]
|
||||
(v{spring-pulsar-version})
|
||||
|
||||
include::overview/copyright.adoc[]
|
||||
|
||||
ifeval::[{is-snapshot-version} == true]
|
||||
CAUTION: You are viewing documentation for a SNAPSHOT version ({spring-pulsar-version}). While it is usually in-sync with the underlying code, it is subject to change and not guaranteed to be up-to-date with the underlying code.
|
||||
endif::[]
|
||||
@@ -0,0 +1,7 @@
|
||||
[[introduction]]
|
||||
= Introduction
|
||||
|
||||
This project provides a basic Spring-friendly API for developing https://pulsar.apache.org/[Apache Pulsar] applications.
|
||||
|
||||
On a very high level, Spring for Apache Pulsar provides a `PulsarTemplate` for publishing to a Pulsar topic and a `PulsarListener` annotation for consuming from a Pulsar topic.
|
||||
In addition, it also provides various convenience APIs for Spring developers to ramp up their development journey into Apache Pulsar.
|
||||
@@ -0,0 +1,25 @@
|
||||
[[building-project]]
|
||||
== Building the Project
|
||||
|
||||
include::../attributes/attributes-variables.adoc[]
|
||||
|
||||
If you have cloned the project locally, follow these steps to build the project from the source code.
|
||||
|
||||
NOTE: Gradle `7.x (7.4 or above)` is required to build.
|
||||
|
||||
Run the following command to do a full build of the project:
|
||||
[indent=0]
|
||||
----
|
||||
./gradlew clean build
|
||||
----
|
||||
You can build without running tests by using the following command:
|
||||
[indent=0]
|
||||
----
|
||||
./gradlew clean build -x test
|
||||
----
|
||||
|
||||
You can build the reference documentation using this command:
|
||||
----
|
||||
./gradlew :spring-pulsar-docs:antora
|
||||
----
|
||||
You can view the generated HTML in `_docs/build/site_` directory.
|
||||
@@ -1,6 +1,7 @@
|
||||
[[getting-help]]
|
||||
= Getting Help
|
||||
include::attributes.adoc[]
|
||||
|
||||
include::../attributes/attributes-variables.adoc[]
|
||||
|
||||
If you have trouble with Spring for Apache Pulsar, we would like to help.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
[[project-status]]
|
||||
= Project Status
|
||||
|
||||
While the code and functionality of the framework is thoroughly tested and ready for production, the project is in a bit of flux while transitioning from experimental GA (`0.2.x`) to GA (`1.0.0`).
|
||||
|
||||
The evolution of the project (by version) is as follows:
|
||||
@@ -0,0 +1,12 @@
|
||||
[[system-requirements]]
|
||||
= System Requirements
|
||||
|
||||
include::../attributes/attributes-variables.adoc[]
|
||||
|
||||
Spring for Apache Pulsar `{spring-pulsar-version}` requires the following:
|
||||
|
||||
- https://www.java.com[Java 17] and is compatible up to and including Java 20
|
||||
- {spring-framework-docs}[Spring Framework `{spring-framework-version}`] or above
|
||||
- {apache-pulsar-cient-docs}/[Apache Pulsar Java Client `{pulsar-client-version}`] or above
|
||||
|
||||
The version compatibility matrix (including Spring Boot) can be found in the xref:appendix/version-compatibility.adoc#version-compatibility[appendix].
|
||||
@@ -0,0 +1,12 @@
|
||||
[[other-resources]]
|
||||
= Other Resources
|
||||
|
||||
include::attributes/attributes-variables.adoc[]
|
||||
|
||||
In addition to this reference documentation, we recommend a number of other resources that may help you learn about Spring and Apache Pulsar.
|
||||
|
||||
- {github}[Spring for Apache Pulsar GitHub Repository]
|
||||
- https://pulsar.apache.org/[Apache Pulsar Project Home Page]
|
||||
- {apache-pulsar-docs}/client-libraries-java/[Apache Pulsar Java Client]
|
||||
- https://github.com/apache/pulsar[Apache Pulsar GitHub Repository]
|
||||
- https://github.com/apache/pulsar-client-reactive[Apache Pulsar Reactive Client GitHub Repository]
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
To connect to a Pulsar cluster that requires authentication, you need to specify which authentication plugin to use and any parameters required by the specified plugin.
|
||||
When **using Spring Boot** auto-configuration, you can set the plugin and the plugin parameters via configuration properties (in most cases).
|
||||
@@ -21,7 +21,6 @@ The following listings show how to configure each of the supported authenticatio
|
||||
[[Athenz]]
|
||||
.[.underline]#Click ##here## for **Athenz**#
|
||||
[%collapsible]
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
@@ -36,13 +35,11 @@ spring:
|
||||
privateKey: ...
|
||||
keyId: ...
|
||||
----
|
||||
NOTE: This also requires TLS encryption as described in <<pulsar.adoc#tls-encryption>>.
|
||||
====
|
||||
NOTE: This also requires xref:reference/pulsar.adoc#tls-encryption[TLS encryption].
|
||||
|
||||
[[Token]]
|
||||
.[.underline]#Click ##here## for **Token**#
|
||||
[%collapsible]
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
@@ -53,12 +50,10 @@ spring:
|
||||
param:
|
||||
token: some-token-goes-here
|
||||
----
|
||||
====
|
||||
|
||||
[[Basic]]
|
||||
.[.underline]#Click ##here## for **Basic**#
|
||||
[%collapsible]
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
@@ -70,12 +65,10 @@ spring:
|
||||
userId: ...
|
||||
password: ...
|
||||
----
|
||||
====
|
||||
|
||||
[[OAuth2]]
|
||||
.[.underline]#Click ##here## for **OAuth2**#
|
||||
[%collapsible]
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
@@ -89,12 +82,10 @@ spring:
|
||||
audience: ...
|
||||
scope: ...
|
||||
----
|
||||
====
|
||||
|
||||
[[Sasl]]
|
||||
.[.underline]#Click ##here## for **Sasl**#
|
||||
[%collapsible]
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
@@ -106,13 +97,12 @@ spring:
|
||||
saslJaasClientSectionName: ...
|
||||
serverType: ...
|
||||
----
|
||||
====
|
||||
|
||||
[[mTlS-pem]]
|
||||
.[.underline]#Click ##here## for **mTLS (PEM)**#
|
||||
[%collapsible]
|
||||
====
|
||||
NOTE: Because this option requires TLS encryption, which already requires you to <<pulsar.adoc#tls-encryption,provide a client builder customizer>>, it is recommended to simply add the authentication directly on the client builder in your provided TLS customizer.
|
||||
NOTE: Because this option requires TLS encryption, which already requires you to xref:reference/pulsar.adoc#tls-encryption[provide a client builder customizer], it is recommended to simply add the authentication directly on the client builder in your provided TLS customizer.
|
||||
You can use the `org.apache.pulsar.client.api.AuthenticationFactory` to help create the authentication object as follows:
|
||||
[source,java]
|
||||
----
|
||||
@@ -125,7 +115,7 @@ See the official Pulsar documentation on {apache-pulsar-docs}/security-tls-authe
|
||||
.[.underline]#Click ##here## for **mTLS (JKS)**#
|
||||
[%collapsible]
|
||||
====
|
||||
NOTE: Because this option requires TLS encryption, which already requires you to <<pulsar.adoc#tls-encryption,provide a client builder customizer>>, it is recommended to simply add the authentication directly on the client builder in your provided TLS customizer.
|
||||
NOTE: Because this option requires TLS encryption, which already requires you to xref:reference/pulsar.adoc#tls-encryption[provide a client builder customizer], it is recommended to simply add the authentication directly on the client builder in your provided TLS customizer.
|
||||
You can use the `org.apache.pulsar.client.api.AuthenticationFactory` to help create the authentication object as follows:
|
||||
[source,java]
|
||||
----
|
||||
@@ -19,9 +19,9 @@ To add other tags to timers and traces, configure a custom `PulsarTemplateObserv
|
||||
|
||||
TIP: You can subclass either `DefaultPulsarTemplateObservationConvention` or `DefaultPulsarListenerObservationConvention` or provide completely new implementations.
|
||||
|
||||
include::observation/_metrics.adoc[]
|
||||
include::partial$_metrics.adoc[]
|
||||
|
||||
include::observation/_spans.adoc[]
|
||||
include::partial$_spans.adoc[]
|
||||
|
||||
See https://micrometer.io/docs/tracing[Micrometer Tracing] for more information.
|
||||
|
||||
@@ -39,8 +39,11 @@ The following example shows the steps to configure your Spring Boot application
|
||||
|
||||
. Add the required dependencies to your application (in Maven or Gradle, respectively):
|
||||
+
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -61,6 +64,7 @@ The following example shows the steps to configure your Spring Boot application
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
======
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
@@ -74,9 +78,7 @@ dependencies {
|
||||
----
|
||||
+
|
||||
NOTE
|
||||
====
|
||||
You need the `'io.zipkin.reporter2:zipkin-sender-urlconnection'` dependency only if your application does not have a configured WebClient or RestTemplate.
|
||||
====
|
||||
. Add the required properties to your application:
|
||||
+
|
||||
[source,yaml,indent=0,subs="verbatim"]
|
||||
@@ -1,6 +1,6 @@
|
||||
[[pulsar-admin]]
|
||||
= Pulsar Administration
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
[[pulsar-admin-client]]
|
||||
== Pulsar Admin Client
|
||||
@@ -18,7 +18,7 @@ See the {spring-boot-pulsar-config-props}[`spring.pulsar.admin.*`] application p
|
||||
[[pulsar-admin-authentication]]
|
||||
=== Authentication
|
||||
When accessing a Pulsar cluster that requires authentication, the admin client requires the same security configuration as the regular Pulsar client.
|
||||
You can use the aforementioned <<pulsar.adoc#client-authentication,security configuration>> by replacing `spring.pulsar.client` with `spring.pulsar.admin`.
|
||||
You can use the aforementioned xref:reference/pulsar.adoc#client-authentication[security configuration] by replacing `spring.pulsar.client` with `spring.pulsar.admin`.
|
||||
|
||||
[[pulsar-auto-topic-creation]]
|
||||
== Automatic Topic Creation
|
||||
@@ -28,7 +28,6 @@ For all such beans, the `PulsarAdministration` either creates the corresponding
|
||||
|
||||
The following example shows how to add `PulsarTopic` beans to let the `PulsarAdministration` auto-create topics for you:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
@@ -43,4 +42,3 @@ PulsarTopic partitionedTopic {
|
||||
return PulsarTopic.builder("persistent://my-tenant/my-namespace/partitioned-topic", 3).build();
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -1,6 +1,6 @@
|
||||
[[pulsar-binder]]
|
||||
= Spring Cloud Stream Binder for Apache Pulsar
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
Spring for Apache Pulsar provides a binder for Spring Cloud Stream that we can use to build event-driven microservices using pub-sub paradigms.
|
||||
In this section, we will go through the basic details of this binder.
|
||||
@@ -11,8 +11,11 @@ TIP: For those unfamiliar with the concepts in Spring Cloud Stream, go through t
|
||||
|
||||
We need to include the following dependency on your application to use Apache Pulsar binder for Spring Cloud Stream.
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -23,13 +26,15 @@ We need to include the following dependency on your application to use Apache Pu
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
dependencies {
|
||||
implementation 'org.springframework.cloud:spring-cloud-stream-binder-pulsar:{spring-cloud-stream-version}'
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
== Overview
|
||||
|
||||
@@ -40,7 +45,6 @@ Applications can start from a middleware-neutral manner and then map Pulsar topi
|
||||
Spring Cloud Stream is built on top of Spring Boot, and when writing an event-driven microservice using Spring Cloud Stream, you are essentially writing a Boot application.
|
||||
Here is a straightforward Spring Cloud Stream application.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@@ -80,7 +84,6 @@ public class SpringPulsarBinderSampleApp {
|
||||
}
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
The above sample application, a full-blown Spring Boot application, deserves a few explanations. However, on a first pass, you can see that this is just plain Java and a few Spring and Spring Boot annotations.
|
||||
We have three `Bean` methods here - a `java.util.function.Supplier`, a `java.util.function.Function`, and finally, a `java.util.function.Consumer`.
|
||||
@@ -191,7 +194,7 @@ This information is provided as extended binding properties.
|
||||
As you can see above in the configuration, the properties are - `spring.cloud.stream.pulsar.bindings.<binding-name>.producer|consumer.schema-type` for schema information and `spring.cloud.stream.pulsar.bindings.<binding-name>.producer|consumer.message-type` for the actual target type.
|
||||
If you have both keys and values on the message, you can use `message-key-type` and `message-value-type` to specify their target types.
|
||||
|
||||
TIP: Any configured <<pulsar.adoc#schema-info-template-imperative,custom schema mappings>> will be consulted when the `schema-type` property is omitted.
|
||||
TIP: Any configured xref:reference/pulsar.adoc#schema-info-template-imperative[custom schema mappings] will be consulted when the `schema-type` property is omitted.
|
||||
|
||||
=== Message Header Conversion
|
||||
Each message typically has header information that needs to be carried along as the message traverses between Pulsar and Spring Messaging via Spring Cloud Stream input and output bindings.
|
||||
@@ -1,6 +1,6 @@
|
||||
[[pulsar-function]]
|
||||
= Pulsar Functions
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
Spring for Apache Pulsar provides basic suppport for {apache-pulsar-io-docs}/[Pulsar IO] (connectors) and {apache-pulsar-function-docs}[Pulsar Functions] which allow users to define stream processing pipelines made up of `sources`, `processors`, and `sinks`.
|
||||
The `sources` and `sinks` are modeled by _Pulsar IO (connectors)_ and the `processors` are represented by _Pulsar Functions_.
|
||||
@@ -24,7 +24,7 @@ The framework provides the `PulsarFunctionAdministration` component to manage Pu
|
||||
When you use the Pulsar Spring Boot starter, you get the `PulsarFunctionAdministration` auto-configured.
|
||||
|
||||
By default, the application tries to connect to a local Pulsar instance at `http://localhost:8080`.
|
||||
However, because it leverages the already configured `PulsarAdministration`, see <<pulsar-admin.adoc#pulsar-admin-client,Pulsar Admin Client>> for available client options (including authentication).
|
||||
However, because it leverages the already configured `PulsarAdministration`, see xref:reference/pulsar-admin.adoc#pulsar-admin-client[Pulsar Admin Client] for available client options (including authentication).
|
||||
Additional configuration options are available with the {spring-boot-pulsar-config-props}[`spring.pulsar.function.*`] application properties.
|
||||
|
||||
== Automatic Function Management
|
||||
@@ -99,7 +99,6 @@ The jar file can be uploaded to the Pulsar package manager and then referenced v
|
||||
Here are some examples that show how to configure a `PulsarSource` bean which results in the `PulsarFunctionAdministration` auto-creating the backing Pulsar source connector.
|
||||
|
||||
.PulsarSource using built-in Rabbit connector
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
@@ -122,12 +121,10 @@ PulsarSource rabbitSource() {
|
||||
return new PulsarSource(sourceConfig, null);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
This next example is the same as the previous, except that it uses the Spring Boot auto-configured `RabbitProperties` to ease the configuration burden. This of course requires the application to be using Spring Boot with Rabbit auto-configuration enabled.
|
||||
|
||||
.PulsarSource using built-in Rabbit connector and Spring Boot RabbitProperties
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
@@ -150,6 +147,5 @@ PulsarSource rabbitSourceWithBootProps(RabbitProperties props) {
|
||||
return new PulsarSource(sourceConfig, null);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
TIP: For a more elaborate example see the link:{github}/blob/main/spring-pulsar-sample-apps/sample-pulsar-functions/README.adoc[Sample Stream Pipeline with Pulsar Functions] sample app
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
include::attributes-variables.adoc[]
|
||||
include::../attributes/attributes-variables.adoc[]
|
||||
|
||||
=== Pulsar Headers
|
||||
Pulsar does not have a first-class "`header`" concept but instead provides a map for custom user properties as well as methods to access the message metadata typically stored in a message header (eg. `id` and `event-time`).
|
||||
@@ -13,7 +13,6 @@ Spring Messaging provides first-class "`header`" support via its `MessageHeaders
|
||||
The `PulsarHeaderMapper` strategy is provided to map headers to and from Pulsar user properties and Spring `MessageHeaders`.
|
||||
|
||||
Its interface definition is as follows:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public interface PulsarHeaderMapper {
|
||||
@@ -23,7 +22,6 @@ public interface PulsarHeaderMapper {
|
||||
MessageHeaders toSpringHeaders(Message<?> pulsarMessage);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The framework provides a couple of mapper implementations.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[[pulsar]]
|
||||
= Using Spring for Apache Pulsar
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
== Preface
|
||||
|
||||
@@ -58,14 +58,12 @@ The template provides a {javadocs}/org/springframework/pulsar/core/PulsarOperati
|
||||
|
||||
==== Message customization
|
||||
You can specify a `TypedMessageBuilderCustomizer` to configure the outgoing message. For example, the following code shows how to send a keyed message:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
template.newMessage(msg)
|
||||
.withMessageCustomizer((mb) -> mb.key("foo-msg-key"))
|
||||
.send();
|
||||
----
|
||||
====
|
||||
|
||||
==== Producer customization
|
||||
You can specify a `ProducerBuilderCustomizer` to configure the underlying Pulsar producer builder that ultimately constructs the producer used to send the outgoing message.
|
||||
@@ -73,37 +71,31 @@ You can specify a `ProducerBuilderCustomizer` to configure the underlying Pulsar
|
||||
WARNING: Use with caution as this gives full access to the producer builder and invoking some of its methods (such as `create`) may have unintended side effects.
|
||||
|
||||
For example, the following code shows how to disable batching and enable chunking:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
template.newMessage(msg)
|
||||
.withProducerCustomizer((pb) -> pb.enableChunking(true).enableBatching(false))
|
||||
.send();
|
||||
----
|
||||
====
|
||||
|
||||
This other example shows how to use custom routing when publishing records to partitioned topics.
|
||||
Specify your custom `MessageRouter` implementation on the `Producer` builder such as:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
template.newMessage(msg)
|
||||
.withProducerCustomizer((pb) -> pb.messageRouter(messageRouter))
|
||||
.send();
|
||||
----
|
||||
====
|
||||
|
||||
TIP: Note that, when using a `MessageRouter`, the only valid setting for `spring.pulsar.producer.message-routing-mode` is `custom`.
|
||||
|
||||
This other example shows how to add a `ProducerInterceptor` that will intercept and mutate messages received by the producer before being published to the brokers:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
template.newMessage(msg)
|
||||
.withProducerCustomizer((pb) -> pb.intercept(interceptor))
|
||||
.send();
|
||||
----
|
||||
====
|
||||
|
||||
[[schema-info-template-imperative]]
|
||||
:template-class: PulsarTemplate
|
||||
@@ -131,7 +123,6 @@ If you use Spring Boot auto-configuration, you can specify the interceptors as B
|
||||
They are passed automatically to the `PulsarTemplate`.
|
||||
Ordering of the interceptors is achieved by using the `@Order` annotation as follows:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@@ -146,7 +137,6 @@ ProducerInterceptor secondInterceptor() {
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: If you are not using the starter, you will need to configure and register the aforementioned components yourself.
|
||||
|
||||
@@ -165,7 +155,6 @@ Spring Boot auto-configuration also provides this consumer factory which you can
|
||||
|
||||
Let us revisit the `PulsarListener` code snippet we saw in the quick-tour section:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar")
|
||||
@@ -173,11 +162,9 @@ public void listen(String message) {
|
||||
System.out.println("Message Received: " + message);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You can further simplify this method:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener
|
||||
@@ -185,7 +172,6 @@ public void listen(String message) {
|
||||
System.out.println("Message Received: " + message);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In this most basic form, you must provide the following two properties with their corresponding values:
|
||||
|
||||
@@ -208,7 +194,6 @@ For any complex types (such as JSON, AVRO, and others), the framework cannot do
|
||||
|
||||
The following example shows another `PulsarListener` method, which takes an `Integer`:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "my-subscription-1", topics = "my-topic-1")
|
||||
@@ -216,11 +201,9 @@ public void listen(Integer message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The following `PulsarListener` method shows how we can consume complex types from a topic:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "my-subscription-2", topics = "my-topic-2", schemaType = SchemaType.JSON)
|
||||
@@ -228,7 +211,6 @@ public void listen(Foo message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Note the addition of a `schemaType` property on `PulsarListener`.
|
||||
That is because the library is not capable of inferring the schema type from the provided type: `Foo`. We must tell the framework what schema to use.
|
||||
@@ -237,7 +219,6 @@ Let us look at a few more ways.
|
||||
|
||||
You can consume the Pulsar message directly:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "my-subscription", topics = "my-topic")
|
||||
@@ -245,11 +226,9 @@ public void listen(org.apache.pulsar.client.api.Message<String> message) {
|
||||
System.out.println(message.getValue());
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The following example consumes the record by using the Spring messaging envelope:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "my-subscription", topics = "my-topic")
|
||||
@@ -257,12 +236,10 @@ public void listen(org.springframework.messaging.Message<String> message) {
|
||||
System.out.println(message.getPayload());
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Now let us see how we can consume records in batches.
|
||||
The following example uses `PulsarListener` to consume records in batches as POJOs:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-batch-subscription", topics = "hello-batch", schemaType = SchemaType.JSON, batch = true)
|
||||
@@ -271,7 +248,6 @@ public void listen(List<Foo> messages) {
|
||||
messages.forEach((message) -> System.out.println("record : " + message));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Note that, in this example, we receive the records as a collection (`List`) of objects.
|
||||
In addition, to enable batch consumption at the `PulsarListener` level, you need to set the `batch` property on the annotation to `true`.
|
||||
@@ -281,7 +257,6 @@ If the `List` contains a complex type, you still need to provide the `schemaType
|
||||
|
||||
The following uses the `Message` envelope provided by the Pulsar Java client:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-batch-subscription", topics = "hello-batch", schemaType = SchemaType.JSON, batch = true)
|
||||
@@ -290,11 +265,9 @@ public void listen(List<Message<Foo>> messages) {
|
||||
messages.forEach((message) -> System.out.println("record : " + message.getValue()));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The following example consumes batch records with an envelope of the Spring messaging `Message` type:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-batch-subscription", topics = "hello-batch", schemaType = SchemaType.JSON, batch = true)
|
||||
@@ -303,11 +276,9 @@ public void listen(List<org.springframework.messaging.Message<Foo>> messages) {
|
||||
messages.forEach((message) -> System.out.println("record : " + message.getPayload()));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Finally, you can also use the `Messages` holder object from Pulsar for the batch listener:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-batch-subscription", topics = "hello-batch", schemaType = SchemaType.JSON, batch = true)
|
||||
@@ -316,21 +287,18 @@ public void listen(org.apache.pulsar.client.api.Messages<Foo>> messages) {
|
||||
messages.forEach((message) -> System.out.println("record : " + message.getValue()));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When you use `PulsarListener`, you can provide Pulsar consumer properties directly on the annotation itself.
|
||||
This is convenient if you do not want to use the Boot configuration properties mentioned earlier or have multiple `PulsarListener` methods.
|
||||
|
||||
The following example uses Pulsar consumer properties directly on `PulsarListener`:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(properties = { "subscriptionName=subscription-1", "topicNames=foo-1", "receiverQueueSize=5000" })
|
||||
void listen(String message) {
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
TIP: The properties used are direct Pulsar consumer properties, not the `spring.pulsar.consumer` application configuration properties
|
||||
|
||||
@@ -342,7 +310,6 @@ include::schema-info/schema-info-listener.adoc[leveloffset=+1]
|
||||
Sometimes, you need direct access to the Pulsar Consumer object.
|
||||
The following example shows how to get it:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar")
|
||||
@@ -352,7 +319,6 @@ public void listen(String message, org.apache.pulsar.client.api.Consumer<String>
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
CAUTION: When accessing the `Consumer` object this way, do NOT invoke any operations that would change the Consumer's cursor position by invoking any receive methods.
|
||||
All such operations must be done by the container.
|
||||
@@ -394,31 +360,26 @@ Before doing so, however, let us take a closer look at the container itself.
|
||||
This is a single consumer-based message listener container.
|
||||
The following listing shows its constructor:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public DefaultPulsarMessageListenerContainer(PulsarConsumerFactory<? super T> pulsarConsumerFactory,
|
||||
PulsarContainerProperties pulsarContainerProperties)
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
It receives a `PulsarConsumerFactory` (which it uses to create the consumer) and a `PulsarContainerProperties` object (which contains information about the container properties).
|
||||
`PulsarContainerProperties` has the following constructors:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public PulsarContainerProperties(String... topics)
|
||||
|
||||
public PulsarContainerProperties(Pattern topicPattern)
|
||||
----
|
||||
====
|
||||
|
||||
You can provide the topic information through `PulsarContainerProperties` or as a consumer property that is provided to the consumer factory.
|
||||
The following example uses the `DefaultPulsarMessageListenerContainer`:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
@@ -435,7 +396,6 @@ DefaultPulsarMessageListenerContainer<String> pulsarListenerContainer = new Defa
|
||||
|
||||
return pulsarListenerContainer;
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: If topic information is not specified when using the listener containers directly, the same <<topic-resolution-process-imperative,topic resolution process>> used by the `PulsarListener` is used with the one exception that the "Message type default" step is **omitted**.
|
||||
|
||||
@@ -446,13 +406,11 @@ If you want to have multiple consumers managed through multiple threads, you nee
|
||||
|
||||
`ConcurrentPulsarMessageListenerContainer` has the following constructor:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public ConcurrentPulsarMessageListenerContainer(PulsarConsumerFactory<? super T> pulsarConsumerFactory,
|
||||
PulsarContainerProperties pulsarContainerProperties)
|
||||
----
|
||||
====
|
||||
|
||||
`ConcurrentPulsarMessageListenerContainer` lets you specify a `concurrency` property through a setter.
|
||||
Concurrency of more than `1` is allowed only on non-exclusive subscriptions (`failover`, `shared`, and `key-shared`).
|
||||
@@ -460,7 +418,6 @@ You can only have the default `1` for concurrency when you have an exclusive sub
|
||||
|
||||
The following example enables `concurrency` through the `PulsarListener` annotation for a `failover` subscription.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(topics = "my-topic", subscriptionName = "subscription-1",
|
||||
@@ -471,7 +428,6 @@ void listen(String message, Consumer<String> consumer) {
|
||||
System.out.println("Current Consumer: " + consumer.getConsumerName());
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding listener, it is assumed that the topic `my-topic` has three partitions.
|
||||
If it is a non-partitioned topic, having concurrency set to `3` does nothing. You get two idle consumers in addition to the main active one.
|
||||
@@ -482,7 +438,6 @@ NOTE: When you use the `Failover` subscription this way on partitioned topics, P
|
||||
|
||||
The following listing shows another example of `PulsarListener`, but with `Shared` subscription and `concurrency` enabled.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(topics = "my-topic", subscriptionName = "subscription-1",
|
||||
@@ -491,7 +446,6 @@ void listen(String message) {
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, the `PulsarListener` creates five different consumers (this time, we assume that the topic has five partitions).
|
||||
|
||||
@@ -507,7 +461,6 @@ Let us take a look at how the message listener container enables both single-rec
|
||||
==== Single Record Consumption
|
||||
Let us revisit our basic `PulsarListener` for the sake of this discussion:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar")
|
||||
@@ -515,7 +468,6 @@ public void listen(String message) {
|
||||
System.out.println("Message Received: " + message);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
With this `PulsarListener` method, we essential ask Spring for Apache Pulsar to invoke the listener method with a single record each time.
|
||||
We mentioned that the message listener container consumes the data in batches using the `batchReceive` method on the consumer.
|
||||
@@ -527,7 +479,6 @@ As you can see in the previous section, `PulsarRecordMessageListener` extends fr
|
||||
==== Batch Consumption
|
||||
The following example shows the `PulsarListener` consuming records in batches:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-batch-subscription", topics = "hello-batch", schemaType = SchemaType.JSON, batch = true)
|
||||
@@ -536,7 +487,6 @@ public void listen4(List<Foo> messages) {
|
||||
messages.forEach((message) -> System.out.println("record : " + message));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When you use this type of `PulsarListener`, the framework detects that you are in batch mode.
|
||||
Since it already received the data in batches by using the Consumer's `batchReceive` method, it hands off the entire batch to the listener method through an adapter for `PulsarBatchMessageListener`.
|
||||
@@ -550,7 +500,6 @@ The list of available headers can be found in {github}/blob/main/spring-pulsar/s
|
||||
|
||||
The following example shows how you can access the various Pulsar Headers in an application that uses the single record mode of consuming:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@PulsarListener(topics = "simpleListenerWithHeaders")
|
||||
@@ -560,7 +509,6 @@ void simpleListenerWithHeaders(String data, @Header(PulsarHeaders.MESSAGE_ID) Me
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, we access the values for the `messageId` and `rawData` message metadata as well as a custom message property named `foo`.
|
||||
The Spring `@Header` annotation is used for each header field.
|
||||
@@ -574,7 +522,6 @@ Note that you can also use the Spring messaging `Message` envelope to carry the
|
||||
|
||||
In this section, we see how to access the various Pulsar Headers in an application that uses a batch consumer:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@PulsarListener(topics = "simpleBatchListenerWithHeaders", batch = true)
|
||||
@@ -584,7 +531,6 @@ void simpleBatchListenerWithHeaders(List<String> data,
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, we consume the data as a `List<String>`.
|
||||
When extracting the various headers, we do so as a `List<>` as well.
|
||||
@@ -613,7 +559,6 @@ In the following sections, we see how acknowledgment works when you use both sin
|
||||
|
||||
Let us revisit our basic single message based `PulsarListener`:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar")
|
||||
@@ -621,7 +566,6 @@ public void listen(String message) {
|
||||
System.out.println("Message Received: " + message);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
It is natural to wonder, how acknowledgment works when you use `PulsarListener`, especially if you are familiar with using Pulsar consumer directly.
|
||||
The answer comes down to the message listener container, as that is the central place in Spring for Apache Pulsar that coordinates all the consumer related activities.
|
||||
@@ -641,7 +585,6 @@ If the application wants the acknowledgment or negative acknowledgment to occur
|
||||
In that case, after handling each record, the message is acknowledged if no error and negatively acknowledged if there was an error.
|
||||
The following example enables `RECORD` ack mode on the Pulsar listener:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar", ackMode = AckMode.RECORD)
|
||||
@@ -649,7 +592,6 @@ public void listen(String message) {
|
||||
System.out.println("Message Received: " + message);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You can also set the listener property, `spring.pulsar.listner.ack-mode`, to set the ack mode application-wide.
|
||||
When doing this, you need not set this on the `PulsarListener` annotation.
|
||||
@@ -660,7 +602,6 @@ In that case, all the `PulsarListener` methods in the application acquire that p
|
||||
You might not always want the framework to send acknowledgments but, rather, do that directly from the application itself.
|
||||
Spring for Apache Pulsar provides a couple of ways to enable manual message acknowledgments. The following example shows one of them:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar", ackMode = AckMode.MANUAL)
|
||||
@@ -669,7 +610,6 @@ public void listen(Message<String> message, Acknowledgment acknowledgment) {
|
||||
acknowledgment.acknowledge();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
A few things merit explanation here. First, we enablE manual ack mode by setting `ackMode` on `PulsarListener`.
|
||||
When enabling manual ack mode, Spring for Apache Pulsar lets the application inject an `Acknowledgment` object.
|
||||
@@ -677,7 +617,6 @@ The framework achieves this by selecting a compatible message listener container
|
||||
|
||||
The `Acknowledgment` object provides the following API methods:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
void acknowledge();
|
||||
@@ -690,7 +629,6 @@ void nack();
|
||||
|
||||
void nack(MessageId messageId);
|
||||
----
|
||||
====
|
||||
|
||||
You can inject this `Acknowledgment` object into your `PulsarListener` while using `MANUAL` ack mode and then call one of the corresponding methods.
|
||||
|
||||
@@ -705,7 +643,6 @@ See the nack methods shown earlier.
|
||||
|
||||
You can also call `acknowledge` directly on the Pulsar consumer:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar", ackMode = AckMode.MANUAL)
|
||||
@@ -719,7 +656,6 @@ public void listen(Message<String> message, Consumer<String> consumer) {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When calling `acknowledge` directly on the underlying consumer, you need to do error handling by yourself.
|
||||
Using the `Acknowledgment` does not require that, as the framework can do that for you.
|
||||
@@ -736,7 +672,6 @@ Note that this may not be the same batch that was batched on the producer side.
|
||||
|
||||
Consider the following batch listener:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar", batch = true)
|
||||
@@ -746,7 +681,6 @@ public void batchListen(List<Foo> messages) {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When all the messages in the incoming collection (`messages` in this example) are processed, the framework acknowledges all of them.
|
||||
|
||||
@@ -761,7 +695,6 @@ It is entirely up to the application to take care of such concerns.
|
||||
When `MANUAL` ack mode is set, Spring for Apache Pulsar selects a compatible message listener container: `PulsarBatchAcknowledgingMessageListener` for batch consumption, which gives you access to an `Acknowledgment` object.
|
||||
The following are the methods available in the `Acknowledgment` API:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
void acknowledge();
|
||||
@@ -774,12 +707,10 @@ void nack();
|
||||
|
||||
void nack(MessageId messageId);
|
||||
----
|
||||
====
|
||||
|
||||
You can inject this `Acknowledgment` object into your `PulsarListener` while using `MANUAL` ack mode.
|
||||
The following listing shows a basic example for a batch based listener:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-subscription", topics = "hello-pulsar")
|
||||
@@ -795,7 +726,6 @@ public void listen(List<Message<String>> messgaes, Acknowlegement acknowledgment
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When you use a batch listener, the message listener container cannot know which record it is currently operating upon.
|
||||
Therefore, to manually acknowledge, you need to use one of the overloaded `acknowledge` method that takes a `MessageId` or a `List<MessageId>`.
|
||||
@@ -814,7 +744,6 @@ If this property has a value above zero and if the Pulsar consumer does not ackn
|
||||
|
||||
You can also specify this property directly as a Pulsar consumer property on the `PulsarListener` itself:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "subscription-1", topics = "topic-1"
|
||||
@@ -823,13 +752,11 @@ public void listen(String s) {
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When you specify `ackTimeout` (as seen in the preceding `PulsarListener` method), if the consumer does not send an acknowledgement within 60 seconds, the message is redelivered by Pulsar to the consumer.
|
||||
|
||||
If you want to specify some advanced backoff options for ack timeout with different delays, you can do the following:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@EnablePulsar
|
||||
@@ -852,7 +779,6 @@ class AckTimeoutRedeliveryConfig {
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, we specify a bean for Pulsar's `RedeliveryBackoff` with a minimum delay of 1 second, a maximum delay of 10 seconds, and a backoff multiplier of 2.
|
||||
After the initial ack timeout occurs, the message redeliveries are controlled through this backoff bean.
|
||||
@@ -864,7 +790,6 @@ When acknowledging negatively, Pulsar consumer lets you specify how the applicat
|
||||
The default is to redeliver the message in one minute, but you can change it by setting `spring.pulsar.consumer.negative-ack-redelivery-delay`.
|
||||
You can also set it as a consumer property directly on `PulsarListener`, as follows:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "subscription-1", topics = "topic-1"
|
||||
@@ -873,11 +798,9 @@ public void listen(String s) {
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You can also specify different delays and backoff mechanisms with a multiplier by providing a `RedeliveryBackoff` bean and providing the bean name as the `negativeAckRedeliveryBackoff` property on the PulsarProducer, as follows:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@EnablePulsar
|
||||
@@ -899,7 +822,6 @@ class NegativeAckRedeliveryConfig {
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== Using Dead Letter Topic from Apache Pulsar for Message Redelivery and Error Handling
|
||||
|
||||
@@ -908,7 +830,6 @@ For the `Exclusive` and `Failover` subscription types, this feature is not avail
|
||||
The basic idea is that, if a message is retried a certain number of times (maybe due to an ack timeout or nack redelivery), once the number of retries are exhausted, the message can be sent to a special topic called the dead letter queue (DLQ).
|
||||
Let us see some details around this feature in action by inspecting some code snippets:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@EnablePulsar
|
||||
@@ -934,7 +855,6 @@ class DeadLetterPolicyConfig {
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
First, we have a special bean for `DeadLetterPolicy`, and it is named as `deadLetterPolicy` (it can be any name as you wish).
|
||||
This bean specifies a number of things, such as the max delivery (10, in this case) and the name of the dead letter topic -- `my-dlq-topic`, in this case.
|
||||
@@ -967,7 +887,6 @@ When you use `PulsarConsumerErrorHandler` from Spring for Apache Pulsar, make su
|
||||
|
||||
Let us see some details by examining a few code snippets:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@EnablePulsar
|
||||
@@ -995,14 +914,12 @@ class PulsarConsumerErrorHandlerConfig {
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Consider the `pulsarConsumerErrorHandler` bean.
|
||||
This creates a bean of type `PulsarConsumerErrorHandler` and uses the default implementation provided out of the box by Spring for Apache Pulsar: `DefaultPulsarConsumerErrorHandler`.
|
||||
`DefaultPulsarConsumerErrorHandler` has a constructor that takes a `PulsarMessageRecovererFactory` and a `org.springframework.util.backoff.Backoff`.
|
||||
`PulsarMessageRecovererFactory` is a functional interface with the following API:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@FunctionalInterface
|
||||
@@ -1018,12 +935,10 @@ public interface PulsarMessageRecovererFactory<T> {
|
||||
}
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
The `recovererForConsumer` method takes a Pulsar consumer and returns a `PulsarMessageRecoverer`, which is another functional interface.
|
||||
Here is the API of `PulsarMessageRecoverer`:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public interface PulsarMessageRecoverer<T> {
|
||||
@@ -1037,7 +952,6 @@ public interface PulsarMessageRecoverer<T> {
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Spring for Apache Pulsar provides an implementation for `PulsarMessageRecovererFactory` called `PulsarDeadLetterPublishingRecoverer` that provides a default implementation that can recover the message by sending it to a Dead Letter Topic (DLT).
|
||||
We provide this implementation to the constructor for the preceding `DefaultPulsarConsumerErrorHandler`.
|
||||
@@ -1054,7 +968,6 @@ In most cases, the same auto-configured `PulsarTemplate` from Spring Boot is suf
|
||||
When using partitioned topics and using custom message routing for the main topic, you must use a different `PulsarTemplate` that does not take the auto-configured `PulsarProducerFactory` that is populated with a value of `custompartition` for `message-routing-mode`.
|
||||
You can use a `PulsarConsumerErrorHandler` with the following blueprint:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@@ -1072,7 +985,6 @@ PulsarConsumerErrorHandler<Integer> pulsarConsumerErrorHandler(PulsarClient puls
|
||||
new FixedBackOff(100, 5));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Note that we are provide a destination resolver to the `PulsarDeadLetterPublishingRecoverer` as the second constructor argument.
|
||||
If not provided, `PulsarDeadLetterPublishingRecoverer` uses `<subscription-name>-<topic-name>-DLT>` as the DLT topic name.
|
||||
@@ -1090,7 +1002,6 @@ Next, we look at how you can use this on batch listeners.
|
||||
|
||||
First, let us look at a batch `PulsarListener` method:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "batch-demo-5-sub", topics = "batch-demo-4", batch = true, concurrency = "3",
|
||||
@@ -1118,7 +1029,6 @@ void dltReceiver(Message<Integer> message) {
|
||||
}
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
Once again, we provide the `pulsarConsumerErrorHandler` property with the `PulsarConsumerErrorHandler` bean name.
|
||||
When you use a batch listener (as shown in the preceding example) and want to use the `PulsarConsumerErrorHandler` from Spring for Apache Pulsar, you need to use manual acknowledgment.
|
||||
@@ -1134,7 +1044,6 @@ At that point, the message is acknowledged by the container, and the listener is
|
||||
Spring for Apache Pulsar provides a convenient way to customize the consumer created by the container used by the `PulsarListener`.
|
||||
Applications can provide a bean for `ConsumerBuilderCustomizer`.
|
||||
Here is an example.
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@@ -1144,11 +1053,9 @@ public ConsumerBuilderCustomizer<String> myCustomizer() {
|
||||
};
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Then this customizer bean name can be provided as an attribute on the `PuslarListener` annotation as shown below.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "my-subscription",
|
||||
@@ -1157,7 +1064,6 @@ void listen(String message) {
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The framework detects the provided bean through the `PulsarListener` and applies this customizer on the Consumer builder before creating the Pulsar Consumer.
|
||||
|
||||
@@ -1172,7 +1078,6 @@ When the Pulsar message listener container is paused, any polling done by the co
|
||||
Similarly, when the container is resumed, the next poll starts returning data if the topic has any new records added while paused.
|
||||
|
||||
To pause or resume a listener container, first obtain the container instance via the `PulsarListenerEndpointRegistry` bean and then invoke the pause/resume API on the container instance - as shown in the snippet below:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Autowired
|
||||
@@ -1183,7 +1088,6 @@ void someMethod() {
|
||||
container.pause();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
TIP: The id parameter passed to `getListenerContainer` is the container id - which will be the value of the `@PulsarListener` id attribute when pausing/resuming a `@PulsarListener`.
|
||||
|
||||
@@ -1199,7 +1103,6 @@ While it is possible to use `PulsarReaderFactory` directly, Spring for Apache Pu
|
||||
This is similar to the same ideas behind `PulsarListener.`
|
||||
Here is a quick example.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarReader(id = "pulsar-reader-demo-id", subscriptionName = "pulsar-reader-demo-subscription",
|
||||
@@ -1208,7 +1111,6 @@ void read(String message) {
|
||||
//...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
As you can see from the above example, `PulsarReader` is a quick way to read from a Pulsar topic.
|
||||
The `id` and `subscriptionName` attributes are optional, but always a best practice to provide them.
|
||||
@@ -1223,7 +1125,6 @@ Suppose you want the reader to start reading messages arbitrarily from a topic o
|
||||
You can customize any fields available through `ReaderBuilder` using a `ReaderBuilderCustomizer` in Spring for Apache Pulsar.
|
||||
You can provide a `@Bean` from `ReaderBuilderCustomizer` and then make it available to the `PulsarReader` as below.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarReader(id = "with-customizer-reader", subscriptionName = "with-customizer-reader-subscription",
|
||||
@@ -1240,7 +1141,6 @@ public ReaderBuilderCustomizer<String> myCustomizer() {
|
||||
};
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[topic-resolution-process-imperative]]
|
||||
== Topic Resolution
|
||||
@@ -1251,7 +1151,6 @@ include::topic-resolution.adoc[leveloffset=+1]
|
||||
In the following example, we publish to a topic called `hello-pulsar-partitioned`.
|
||||
It is a topic that is partitioned, and, for this sample, we assume that the topic is already created with three partitions.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@@ -1304,7 +1203,6 @@ public class PulsarBootPartitioned {
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, we publish to a partitioned topic, and we would like to publish some data segment to a specific partition.
|
||||
If you leave it to Pulsar's default, it follows a round-robin mode of partition assignments, and we would like to override that.
|
||||
@@ -1320,7 +1218,6 @@ This means that data from all the partitions ends up in the same consumer and th
|
||||
What can we do if we want each partition to be consumed by a single distinct consumer?
|
||||
We can switch to the `failover` subscription mode and add three separate consumers:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-partitioned-subscription", topics = "hello-pulsar-partitioned", subscriptionType = SubscriptionType.Failover)
|
||||
@@ -1338,7 +1235,6 @@ public void listen3(String foo) {
|
||||
System.out.println("Message Received 3: " + foo);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When you follow this approach, a single partition always gets consumed by a dedicated consumer.
|
||||
|
||||
@@ -1347,7 +1243,6 @@ However, when you use the `shared` mode, you lose any ordering guarantees, as a
|
||||
|
||||
Consider the following example:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "hello-pulsar-shared-subscription", topics = "hello-pulsar-partitioned", subscriptionType = SubscriptionType.Shared)
|
||||
@@ -1360,4 +1255,3 @@ public void listen2(String foo) {
|
||||
System.out.println("Message Received 2: " + foo);
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -1,6 +1,6 @@
|
||||
[[quick-tour]]
|
||||
= Quick Tour
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
We will take a quick tour of Spring for Apache Pulsar by showing a sample Spring Boot application that produces and consumes.
|
||||
This is a complete application and does not require any additional configuration, as long as you have a Pulsar cluster running on the default location - `localhost:6650`.
|
||||
@@ -8,8 +8,11 @@ This is a complete application and does not require any additional configuration
|
||||
== Dependencies
|
||||
Spring Boot applications need only the `spring-pulsar-spring-boot-starter` dependency. The following listings show how to define the dependency for Maven and Gradle, respectively:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -20,20 +23,25 @@ Spring Boot applications need only the `spring-pulsar-spring-boot-starter` depen
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-pulsar:{spring-boot-version}'
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
[CAUTION]
|
||||
====
|
||||
When using `Version 0.2.x` the above coordinates change as follows:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -43,13 +51,16 @@ When using `Version 0.2.x` the above coordinates change as follows:
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
dependencies {
|
||||
implementation 'org.springframework.pulsar:spring-pulsar-spring-boot-starter:0.2.0'
|
||||
}
|
||||
----
|
||||
======
|
||||
====
|
||||
|
||||
== Application Code
|
||||
@@ -1,6 +1,6 @@
|
||||
[[reactive-pulsar]]
|
||||
= Reactive Support
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
The framework provides a Reactive counterpart for almost all supported features.
|
||||
|
||||
@@ -56,7 +56,7 @@ See the {spring-boot-pulsar-config-props}[`spring.pulsar.client.*`] application
|
||||
|
||||
[[reactive-client-authentication]]
|
||||
=== Authentication
|
||||
To connect to a Pulsar cluster that requires authentication, follow <<pulsar.adoc#client-authentication,the same steps>> as the imperative client.
|
||||
To connect to a Pulsar cluster that requires authentication, follow xref:reference/pulsar.adoc#client-authentication[the same steps] as the imperative client.
|
||||
Again, this is because the reactive client adapts the imperative client which handles all security configuration.
|
||||
|
||||
[[reactive-message-production]]
|
||||
@@ -76,14 +76,12 @@ The template provides a {javadocs}/org/springframework/pulsar/reactive/core/Reac
|
||||
|
||||
==== Message customization
|
||||
You can specify a `MessageSpecBuilderCustomizer` to configure the outgoing message. For example, the following code shows how to send a keyed message:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
template.newMessage(msg)
|
||||
.withMessageCustomizer((mc) -> mc.key("foo-msg-key"))
|
||||
.send();
|
||||
----
|
||||
====
|
||||
|
||||
==== Sender customization
|
||||
You can specify a `ReactiveMessageSenderBuilderCustomizer` to configure the underlying Pulsar sender builder that ultimately constructs the sender used to send the outgoing message.
|
||||
@@ -91,25 +89,21 @@ You can specify a `ReactiveMessageSenderBuilderCustomizer` to configure the unde
|
||||
WARNING: Use with caution as this gives full access to the sender builder and invoking some of its methods (such as `create`) may have unintended side effects.
|
||||
|
||||
For example, the following code shows how to disable batching and enable chunking:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
template.newMessage(msg)
|
||||
.withSenderCustomizer((sc) -> sc.enableChunking(true).enableBatching(false))
|
||||
.send();
|
||||
----
|
||||
====
|
||||
|
||||
This other example shows how to use custom routing when publishing records to partitioned topics.
|
||||
Specify your custom `MessageRouter` implementation on the sender builder such as:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
template.newMessage(msg)
|
||||
.withSenderCustomizer((sc) -> sc.messageRouter(messageRouter))
|
||||
.send();
|
||||
----
|
||||
====
|
||||
|
||||
TIP: Note that, when using a `MessageRouter`, the only valid setting for `spring.pulsar.reactive.sender.message-routing-mode` is `custom`.
|
||||
|
||||
@@ -144,7 +138,6 @@ When you use Spring Boot support, it automatically enables this annotation and c
|
||||
|
||||
Let us revisit the `ReactivePulsarListener` code snippet we saw in the quick-tour section:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ReactivePulsarListener(subscriptionName = "hello-pulsar-sub", topics = "hello-pulsar-topic")
|
||||
@@ -153,12 +146,10 @@ Mono<Void> listen(String message) {
|
||||
return Mono.empty();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: The listener method returns a `Mono<Void>` to signal whether the message was successfully processed. `Mono.empty()` indicates success (acknowledgment) and `Mono.error()` indicates failure (negative acknowledgment).
|
||||
|
||||
You can also further simplify this method:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ReactivePulsarListener
|
||||
@@ -167,7 +158,6 @@ Mono<Void> listen(String message) {
|
||||
return Mono.empty();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In this most basic form, you must still provide the topic name by setting the following property:
|
||||
|
||||
@@ -190,7 +180,6 @@ For all the primitive types in Java, the framework does this inference.
|
||||
For any complex types (such as JSON, AVRO, and others), the framework cannot do this inference and the user needs to provide the schema type on the annotation using the `schemaType` property.
|
||||
|
||||
This example shows how we can consume complex types from a topic:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ReactivePulsarListener(topics = "my-topic-2", schemaType = SchemaType.JSON)
|
||||
@@ -199,7 +188,6 @@ Mono<Void> listen(Foo message) {
|
||||
return Mono.empty();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Note the addition of a `schemaType` property on `ReactivePulsarListener`.
|
||||
That is because the library is not capable of inferring the schema type from the provided type: `Foo`. We must tell the framework what schema to use.
|
||||
@@ -207,7 +195,6 @@ That is because the library is not capable of inferring the schema type from the
|
||||
Let us look at a few more ways we can consume.
|
||||
|
||||
This example consumes the Pulsar message directly:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ReactivePulsarListener(topics = "my-topic")
|
||||
@@ -216,10 +203,8 @@ Mono<Void> listen(org.apache.pulsar.client.api.Message<String> message) {
|
||||
return Mono.empty();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
This example consumes the record wrapped in a Spring messaging envelope:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ReactivePulsarListener(topics = "my-topic")
|
||||
@@ -228,7 +213,6 @@ Mono<Void> listen(org.springframework.messaging.Message<String> message) {
|
||||
return Mono.empty();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== Streaming
|
||||
All of the above are examples of consuming a single record one-by-one.
|
||||
@@ -236,7 +220,6 @@ However, one of the compelling reasons to use Reactive is for the streaming capa
|
||||
|
||||
The following example uses `ReactivePulsarListener` to consume a stream of POJOs:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ReactivePulsarListener(topics = "streaming-1", stream = true)
|
||||
@@ -245,7 +228,6 @@ Flux<MessageResult<Void>> listen(Flux<Message<String>> messages) {
|
||||
.doOnNext((msg) -> System.out.println("Received: " + msg.getValue()))
|
||||
.map(MessageResult::acknowledge);
|
||||
----
|
||||
====
|
||||
Here we receive the records as a `Flux` of messages.
|
||||
In addition, to enable stream consumption at the `ReactivePulsarListener` level, you need to set the `stream` property on the annotation to `true`.
|
||||
|
||||
@@ -255,7 +237,6 @@ Based on the actual type of the messages in the `Flux`, the framework tries to i
|
||||
If it contains a complex type, you still need to provide the `schemaType` on `ReactivePulsarListener`.
|
||||
|
||||
The following listener uses the Spring messaging `Message` envelope with a complex type :
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ReactivePulsarListener(topics = "streaming-2", stream = true, schemaType = SchemaType.JSON)
|
||||
@@ -265,7 +246,6 @@ Flux<MessageResult<Void>> listen2(Flux<org.springframework.messaging.Message<Foo
|
||||
.map(MessageResult::acknowledge);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== Configuration - Application Properties
|
||||
The listener ultimately relies on `ReactivePulsarConsumerFactory` to create and manage the underlying Pulsar consumer.
|
||||
@@ -281,7 +261,6 @@ WARNING: Use with caution as this gives full access to the consumer builder and
|
||||
|
||||
For example, the following code shows how to set the initial position of the subscription to the earliest messaage on the topic.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ReactivePulsarListener(topics = "hello-pulsar-topic", consumerCustomizer = "myConsumerCustomizer")
|
||||
@@ -295,14 +274,12 @@ ReactiveMessageConsumerBuilderCustomizer<String> myConsumerCustomizer() {
|
||||
return b -> b.subscriptionInitialPosition(SubscriptionInitialPosition.Earliest);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
You can also use the customizer to provide direct Pulsar consumer properties to the consumer builder.
|
||||
This is convenient if you do not want to use the Boot configuration properties mentioned earlier or have multiple `ReactivePulsarListener` methods whose configuration varies.
|
||||
|
||||
The following customizer example uses direct Pulsar consumer properties:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@@ -310,7 +287,6 @@ ReactiveMessageConsumerBuilderCustomizer<String> directConsumerPropsCustomizer()
|
||||
return b -> b.property("subscriptionName", "subscription-1").property("topicNames", "foo-1");
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
CAUTION: The properties used are direct Pulsar consumer properties, not the `spring.pulsar.reactive.consumer` Spring Boot configuration properties
|
||||
|
||||
@@ -368,7 +344,6 @@ The list of available headers can be found in {github}/blob/main/spring-pulsar/s
|
||||
==== Accessing In OneByOne Listener
|
||||
The following example shows how you can access Pulsar Headers when using a one-by-one message listener:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@ReactivePulsarListener(topics = "some-topic")
|
||||
@@ -379,7 +354,6 @@ Mono<Void> listen(String data,
|
||||
return Mono.empty();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In the preceding example, we access the values for the `messageId` message metadata as well as a custom message property named `foo`.
|
||||
The Spring `@Header` annotation is used for each header field.
|
||||
@@ -421,7 +395,6 @@ If this property has a value above zero and if the Pulsar consumer does not ackn
|
||||
|
||||
You can also specify this property directly as a Pulsar consumer property via a <<reactive-consumer-customizer,consumer customizer>> such as:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@@ -429,7 +402,6 @@ ReactiveMessageConsumerBuilderCustomizer<String> consumerCustomizer() {
|
||||
return b -> b.property("ackTimeout", "60s");
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== Negative Acknowledgment Redelivery Delay
|
||||
When acknowledging negatively, Pulsar consumer lets you specify how the application wants the message to be re-delivered.
|
||||
@@ -437,7 +409,6 @@ The default is to redeliver the message in one minute, but you can change it by
|
||||
|
||||
You can also set it directly as a Pulsar consumer property via a <<reactive-consumer-customizer,consumer customizer>> such as:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@@ -445,7 +416,6 @@ ReactiveMessageConsumerBuilderCustomizer<String> consumerCustomizer() {
|
||||
return b -> b.property("negativeAckRedeliveryDelay", "10ms");
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== Dead Letter Topic
|
||||
Apache Pulsar lets applications use a dead letter topic on consumers with a `Shared` subscription type.
|
||||
@@ -453,7 +423,6 @@ For the `Exclusive` and `Failover` subscription types, this feature is not avail
|
||||
The basic idea is that, if a message is retried a certain number of times (maybe due to an ack timeout or nack redelivery), once the number of retries are exhausted, the message can be sent to a special topic called the dead letter queue (DLQ).
|
||||
Let us see some details around this feature in action by inspecting some code snippets:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -484,7 +453,6 @@ class DeadLetterPolicyConfig {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
First, we have a special bean for `DeadLetterPolicy`, and it is named as `deadLetterPolicy` (it can be any name as you wish).
|
||||
This bean specifies a number of things, such as the max delivery (10, in this case) and the name of the dead letter topic -- `my-dlq-topic`, in this case.
|
||||
@@ -1,6 +1,6 @@
|
||||
[[quick-tour-reactive]]
|
||||
= Quick Tour
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
We will take a quick tour of the Reactive support in Spring for Apache Pulsar by showing a sample Spring Boot application that produces and consumes in a Reactive fashion.
|
||||
This is a complete application and does not require any additional configuration, as long as you have a Pulsar cluster running on the default location - `localhost:6650`.
|
||||
@@ -9,8 +9,11 @@ This is a complete application and does not require any additional configuration
|
||||
|
||||
Spring Boot applications need only the `spring-pulsar-reactive-spring-boot-starter` dependency. The following listings show how to define the dependency for Maven and Gradle, respectively:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -20,20 +23,26 @@ Spring Boot applications need only the `spring-pulsar-reactive-spring-boot-start
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-pulsar-reactive:{spring-boot-version}'
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
[CAUTION]
|
||||
====
|
||||
When using `Version 0.2.x` the above coordinates change as follows:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Maven
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -43,13 +52,16 @@ When using `Version 0.2.x` the above coordinates change as follows:
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
||||
.Gradle
|
||||
----
|
||||
dependencies {
|
||||
implementation 'org.springframework.pulsar:spring-pulsar-reactive-spring-boot-starter:0.2.0'
|
||||
}
|
||||
----
|
||||
======
|
||||
====
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[[reference]]
|
||||
= Reference
|
||||
|
||||
This part of the reference documentation details the various components that comprise Spring for Apache Pulsar.
|
||||
@@ -1,4 +1,3 @@
|
||||
====
|
||||
[source,java,subs="attributes,verbatim"]
|
||||
----
|
||||
@PulsarListener(subscriptionName = "user-sub", topics = "user-topic")
|
||||
@@ -6,4 +5,3 @@ public void listen(User user) {
|
||||
System.out.println(user);
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -1,4 +1,3 @@
|
||||
====
|
||||
[source,java,subs="attributes,verbatim"]
|
||||
----
|
||||
@ReactivePulsarListener(topics = "user-topic")
|
||||
@@ -7,4 +6,3 @@ Mono<Void> listen(User user) {
|
||||
return Mono.empty();
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -22,7 +22,6 @@ However, if more control is needed you can provide a schema resolver customizer
|
||||
|
||||
The following example uses a schema resolver customizer to add mappings for the `User` and `Address` complex objects using `AVRO` and `JSON` schemas, respectively:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@@ -33,4 +32,3 @@ public SchemaResolverCustomizer<DefaultSchemaResolver> schemaResolverCustomizer(
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -1,5 +1,4 @@
|
||||
== Specifying Schema Information
|
||||
|
||||
As indicated earlier, for Java primitives, the Spring for Apache Pulsar framework can infer the proper Schema to use on the `{listener-class}`.
|
||||
For non-primitive types, if the Schema is not explicitly specified on the annotation, the Spring for Apache Pulsar framework will try to build a `Schema.JSON` from the type.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
include::attributes.adoc[]
|
||||
include::../attributes/attributes.adoc[]
|
||||
|
||||
By default, Pulsar clients communicate with Pulsar services in plain text.
|
||||
The following section describes how to configure Pulsar clients to use TLS encryption (SSL).
|
||||
@@ -1,31 +0,0 @@
|
||||
@import 'css/spring.css';
|
||||
|
||||
.listingblock .switch {
|
||||
border-style: none;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
bottom: -3px;
|
||||
}
|
||||
|
||||
.listingblock .switch--item {
|
||||
padding: 10px;
|
||||
background-color: #e6e1dc;
|
||||
color: #282c34;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.listingblock .switch--item:not(:first-child) {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
.listingblock .switch--item.selected {
|
||||
background-color: #282c34;
|
||||
color: #e6e1dc;
|
||||
}
|
||||
|
||||
.listingblock pre.highlightjs {
|
||||
padding: 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
[[spring-pulsar-reference]]
|
||||
= Spring for Apache Pulsar
|
||||
include::attributes.adoc[]
|
||||
|
||||
include::authors.adoc[]
|
||||
(v{spring-pulsar-version})
|
||||
|
||||
include::copyright.adoc[]
|
||||
|
||||
ifeval::[{is-snapshot-version} == true]
|
||||
CAUTION: You are viewing documentation for a SNAPSHOT version ({spring-pulsar-version}). While it is usually in-sync with the underlying code, it is subject to change and not guaranteed to be up-to-date with the underlying code.
|
||||
endif::[]
|
||||
|
||||
include::intro.adoc[leveloffset=+1]
|
||||
|
||||
include::getting-help.adoc[leveloffset=+2]
|
||||
|
||||
[[reference]]
|
||||
== Reference
|
||||
This part of the reference documentation goes through the details of the various components in Spring for Apache Pulsar.
|
||||
|
||||
include::pulsar.adoc[leveloffset=+2]
|
||||
|
||||
include::reactive-pulsar.adoc[leveloffset=+2]
|
||||
|
||||
include::pulsar-admin.adoc[leveloffset=+2]
|
||||
|
||||
include::pulsar-function.adoc[leveloffset=+2]
|
||||
|
||||
include::observability.adoc[leveloffset=+2]
|
||||
|
||||
include::pulsar-binder.adoc[leveloffset=+2]
|
||||
|
||||
:sectnums!:
|
||||
[[other-resources]]
|
||||
== Other Resources
|
||||
|
||||
In addition to this reference documentation, we recommend a number of other resources that may help you learn about Spring and Apache Pulsar.
|
||||
|
||||
- {github}[Spring for Apache Pulsar GitHub Repository]
|
||||
- https://pulsar.apache.org/[Apache Pulsar Project Home Page]
|
||||
- {apache-pulsar-docs}/client-libraries-java/[Apache Pulsar Java Client]
|
||||
- https://github.com/apache/pulsar[Apache Pulsar GitHub Repository]
|
||||
- https://github.com/apache/pulsar-client-reactive[Apache Pulsar Reactive Client GitHub Repository]
|
||||
|
||||
[[appendix]]
|
||||
== Appendices
|
||||
|
||||
include::version-compatibility.adoc[leveloffset=+2]
|
||||
|
||||
include::override-boot-dependencies.adoc[leveloffset=+2]
|
||||
|
||||
include::non-ga-versions.adoc[leveloffset=+2]
|
||||
|
||||
include::native-image.adoc[leveloffset=+2]
|
||||
@@ -1,38 +0,0 @@
|
||||
|
||||
include::attributes-variables.adoc[]
|
||||
|
||||
= Introduction
|
||||
This project provides a basic Spring-friendly API for developing https://pulsar.apache.org/[Apache Pulsar] applications.
|
||||
|
||||
On a very high level, Spring for Apache Pulsar provides a `PulsarTemplate` for publishing to a Pulsar topic and a `PulsarListener` annotation for consuming from a Pulsar topic.
|
||||
In addition, it also provides various convenience APIs for Spring developers to ramp up their development journey into Apache Pulsar.
|
||||
|
||||
include::project-state.adoc[leveloffset=+1]
|
||||
|
||||
== System Requirements
|
||||
|
||||
Spring for Apache Pulsar `{spring-pulsar-version}` requires the following:
|
||||
|
||||
- https://www.java.com[Java 17] and is compatible up to and including Java 20
|
||||
- {spring-framework-docs}[Spring Framework `{spring-framework-version}`] or above
|
||||
- {apache-pulsar-cient-docs}/[Apache Pulsar Java Client `{pulsar-client-version}`] or above
|
||||
|
||||
====
|
||||
The version compatibility matrix (including Spring Boot) can be found in the <<version-compatibility.adoc#appendix.version-compatibility,appendix>>.
|
||||
====
|
||||
|
||||
== Building the Project
|
||||
If you have cloned the project locally, follow these steps to build the project from the source code.
|
||||
|
||||
NOTE: Gradle `7.x (7.4 or above)` is required to build.
|
||||
|
||||
Run the following command to do a full build of the project:
|
||||
[indent=0]
|
||||
----
|
||||
./gradlew clean build
|
||||
----
|
||||
You can build without running tests by using the following command:
|
||||
[indent=0]
|
||||
----
|
||||
./gradlew clean build -x test
|
||||
----
|
||||
@@ -117,9 +117,6 @@ public final class DefaultReactivePulsarSenderFactory<T>
|
||||
private ReactiveMessageSender<T> doCreateReactiveMessageSender(Schema<T> schema, @Nullable String topic,
|
||||
@Nullable List<ReactiveMessageSenderBuilderCustomizer<T>> customizers) {
|
||||
Objects.requireNonNull(schema, "Schema must be specified");
|
||||
|
||||
this.logger.warn(() -> "**** Du CreateMessageSender for topic=" + topic);
|
||||
|
||||
String resolvedTopic = this.topicResolver.resolveTopic(topic, () -> getDefaultTopic()).orElseThrow();
|
||||
this.logger.trace(() -> "Creating reactive message sender for '%s' topic".formatted(resolvedTopic));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user