-
Notifications
You must be signed in to change notification settings - Fork 46
Add Event-Driven Request-Reply with Azure Event Hub #215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughAdds a new documentation page describing a Kafka request–reply pattern using WSO2 Integrator: BI with Azure Event Hub (Kafka-compatible), covering architecture, Azure provisioning, SASL_SSL/JAAS setup, service build/deploy/test steps, troubleshooting, and cleanup instructions. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
Pre-merge checks❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Fix all issues with AI Agents 🤖
In
@en/docs/integration-guides/event-integration/kafka/request-reply-with-azure-event-hub.md:
- Line 208: Replace bolded step headers that use **Step X.Y: ...** with proper
markdown heading syntax by converting them to level-3 headings (e.g., change
"**Step 3.1: Create a resource group**" to "### Step 3.1: Create a resource
group"); apply the same replacement for other bold step headers in this document
(for example any occurrences of "**Step 3.2:**", "**Step 3.3:**", etc.) so the
sections are real headings and will be picked up by TOC and accessibility
tooling.
🧹 Nitpick comments (2)
en/docs/integration-guides/event-integration/kafka/request-reply-with-azure-event-hub.md (2)
273-273: Specify language for code blocks to enable proper syntax highlighting.Code blocks throughout the document are missing language specifications (e.g.,
```json,```bash). Add appropriate language identifiers after the opening backticks for better readability.Examples requiring fixes:
- Line 273: JSON output →
```json- Line 563, 581: Command output →
```text- Line 598, 606, 613: Logs/responses →
```text- Line 630: JAAS config →
```propertiesor```textAlso applies to: 563-563, 581-581, 598-598, 606-606, 613-613, 630-630
437-437: Fix inline code formatting in string examples.Lines with string value examples have spaces between
stringand the backtick, creating awkward formatting. Combine them into single inline code blocks:Change from:
string[Example text]
Change to:`string `[Example text]``Apply to:
- Line 437: Message parameter
- Line 445: Response variable expression
- Line 460: Log message
- Line 501: Log message
- Line 548: Log message
Also applies to: 445-445, 460-460, 501-501, 548-548
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
en/docs/integration-guides/event-integration/kafka/request-reply-with-azure-event-hub.md
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
en/docs/integration-guides/event-integration/kafka/request-reply-with-azure-event-hub.md
66-66: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
67-67: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
158-158: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
168-168: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
174-174: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
188-188: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
200-200: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
208-208: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
210-210: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
216-216: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
218-218: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
226-226: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
228-228: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
236-236: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
238-238: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
248-248: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
261-261: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
273-273: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
273-273: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
284-284: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
294-294: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
294-294: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
371-371: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
371-371: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
437-437: Spaces inside code span elements
(MD038, no-space-in-code)
445-445: Spaces inside code span elements
(MD038, no-space-in-code)
452-452: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
460-460: Spaces inside code span elements
(MD038, no-space-in-code)
501-501: Spaces inside code span elements
(MD038, no-space-in-code)
507-507: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
514-514: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
548-548: Spaces inside code span elements
(MD038, no-space-in-code)
556-556: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
563-563: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
563-563: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
574-574: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
581-581: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
581-581: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
590-590: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
598-598: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
598-598: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
606-606: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
606-606: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
613-613: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
613-613: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
630-630: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
630-630: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
666-666: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
678-678: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
🔇 Additional comments (1)
en/docs/integration-guides/event-integration/kafka/request-reply-with-azure-event-hub.md (1)
1-50: Comprehensive documentation with solid technical content.The tutorial effectively covers the request-reply pattern with Azure Event Hub. Architecture is clearly explained, prerequisites are thorough, and step-by-step instructions are detailed. The inclusion of both CLI and portal approaches, troubleshooting section, and cleanup guidance demonstrates good documentation practices.
| - Decoupling services while maintaining communication | ||
| - Building scalable microservices architectures | ||
|
|
||
| ## Cleanup: Delete Azure Resources |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this part for the guide ?
|
|
||
| Deleting the resource group stops all charges immediately. | ||
|
|
||
| ## Next Steps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the importance of this section ?
| 5. Type the resource group name to confirm | ||
| 6. Click **Delete** | ||
|
|
||
| ### Cost Information |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
| @@ -0,0 +1,710 @@ | |||
| # Request-Reply with Azure Event Hub | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # Request-Reply with Azure Event Hub | |
| # Implementing request–reply messaging using Azure Event Hub |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename the file name like <topic>.md
As an example if the topic is Implementing request–reply messaging using Azure Event Hub the file can be named as implementing-request–reply-messaging-using-azure-event-hub.md.
And if needed we can use a short form like request-reply-messaging-with-azure-event-hub.md. But lets do this consciously.
|
|
||
| In this tutorial, you will learn how to build a simple request-reply messaging pattern using Azure Event Hub with the Kafka event handler and WSO2 Integrator: BI. You'll create two services that communicate bidirectionally through Event Hub topics. | ||
|
|
||
| ## What You'll Learn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All headers below Level 1 should use sentence case.
| ## What You'll Learn | |
| ## What you'll learn |
| - Build a Reply Service that consumes requests and sends back responses | ||
| - Implement the request-reply pattern using two Event Hub topics | ||
|
|
||
| ## Architecture Overview |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ## Architecture Overview | |
| ## Architecture overview |
| - **Request Service**: Exposes an HTTP endpoint to trigger requests, sends messages to the requests topic, and listens on the responses topic for replies. | ||
| - **Reply Service**: Listens on the requests topic, processes incoming messages, and publishes responses to the responses topic. | ||
|
|
||
| ### Request-Reply Pattern |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ### Request-Reply Pattern | |
| ### Request-reply pattern |
|
|
||
| The Request-Reply pattern is a messaging pattern where a requestor sends a message and expects a correlated response from a replier. | ||
|
|
||
| #### How it Works |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| #### How it Works | |
| #### How it works |
| 3. Replier publishes the response to a REPLY channel (topic) | ||
| 4. Requestor consumes the response from the reply channel | ||
|
|
||
| #### Key Components |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| #### Key Components | |
| #### Key components |
|
|
||
| When you're done with this tutorial, delete the Azure resources to avoid ongoing charges. | ||
|
|
||
| ### Option 1: Delete Using Azure CLI (Recommended) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ### Option 1: Delete Using Azure CLI (Recommended) | |
| ### Option 1: Delete using Azure CLI (Recommended) |
| - Ensure port 9093 is not blocked by firewall | ||
| - Check the connection string is complete | ||
|
|
||
| ### Authentication Failed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ### Authentication Failed | |
| ### Authentication failed |
| - The `$ConnectionString` must be a literal string (not a variable) | ||
| - The password must be your complete connection string starting with `Endpoint=sb://...` | ||
|
|
||
| ### No Messages Received |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ### No Messages Received | |
| ### No messages received |
| Running executable | ||
| ``` | ||
|
|
||
| ### Step 3: Send a Test Request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ### Step 3: Send a Test Request | |
| ### Step 3: Send a test request |
| Running executable | ||
| ``` | ||
|
|
||
| ### Step 2: Start the Request Service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ### Step 2: Start the Request Service | |
| ### Step 2: Start the request service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI Agents
In
@en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md:
- Line 210: Replace all bold step headers like "**Step X.Y: ...**" with proper
markdown headings using appropriate levels (e.g., use "### Step 3.1: Create a
resource group" instead of bold text) and convert every header below level 1 to
sentence case (capitalize only the first word and proper nouns). Specifically
update the occurrences similar to "Step 3.1: Create a resource group" and the
other step headers at the commented lines (218, 228, 238, 259, 282 and any other
"**Step X.Y: ...**" instances) and apply sentence case fixes to all headers
listed in the comment (e.g., change "What You'll Learn" → "What you'll learn",
"Architecture Overview" → "Architecture overview", "Request-Reply Pattern" →
"Request-reply pattern", "Step 4: Get Connection String" → "Step 4: Get
connection string", "Step 5: Verify Your Setup" → "Step 5: Verify your setup",
plus the additional line numbers provided). Ensure heading level syntax (##,
###) replaces bold formatting so TOC and screen readers can parse the structure.
🧹 Nitpick comments (2)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md (2)
275-275: Add language specifications to fenced code blocks.Several code blocks are missing language identifiers, reducing syntax highlighting and readability:
- Line 275: Connection string output (use
textor leave unlabeled for plaintext)- Line 296: Table output (use
text)- Line 373: JAAS config (use
text)- Line 567, 585, 602, 610, 617: Service output logs (use
text)- Line 634: JAAS config example (use
text)For command outputs and plaintext, use
```textinstead of just```.🔎 Example fixes for missing language specs
-Endpoint=sb://kafka-eventhub-demo.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=abc123… +```text +Endpoint=sb://kafka-eventhub-demo.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=abc123… +``` -``` -[ +```text +[Also applies to: 296-296, 373-373, 567-567, 585-585, 602-602, 610-610, 617-617, 634-634
441-441: Review spacing in inline code expressions (potential false positive).Linting flagged spaces inside inline code spans at lines 441, 449, 464, 505, 552 (e.g.,
`[content]`). However, these appear to be intentional Ballerina string interpolation syntax (template literals) rather than markdown code formatting violations. Verify that these are formatted as intended and not actual spacing issues.Also applies to: 449-449, 464-464, 505-505, 552-552
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (7)
en/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/1-create-reply-service-project.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/2-create-kafka-producer-connection.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-2-create-kafka-event-handler.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-3-create-kafka-event-handler.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-create-kafka-event-handler.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/4-add-foreach-block.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/architecture-diagram.pngis excluded by!**/*.png
📒 Files selected for processing (1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-12T05:34:19.589Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 169
File: en/docs/deploy/deployment-best-practices/network-level-security.md:1-20
Timestamp: 2025-11-12T05:34:19.589Z
Learning: In the wso2/docs-bi repository documentation files, using h3 (###) subsection headings directly under h1 (#) titles is an intentional style choice, even though it violates standard markdown heading increment rules.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
📚 Learning: 2025-11-12T05:34:18.459Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 169
File: en/docs/deploy/deployment-best-practices/os-level-security.md:1-25
Timestamp: 2025-11-12T05:34:18.459Z
Learning: In the WSO2 docs-bi repository, specifically in deployment best practices documentation files under en/docs/deploy/deployment-best-practices/, using h3 (###) headings directly after h1 titles (instead of h2) is intentional and should not be flagged.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
🪛 markdownlint-cli2 (0.18.1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
68-68: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
69-69: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
160-160: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
170-170: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
176-176: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
190-190: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
202-202: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
210-210: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
212-212: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
218-218: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
220-220: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
228-228: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
230-230: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
238-238: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
240-240: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
250-250: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
263-263: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
275-275: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
275-275: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
286-286: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
296-296: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
296-296: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
373-373: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
373-373: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
441-441: Spaces inside code span elements
(MD038, no-space-in-code)
449-449: Spaces inside code span elements
(MD038, no-space-in-code)
456-456: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
464-464: Spaces inside code span elements
(MD038, no-space-in-code)
505-505: Spaces inside code span elements
(MD038, no-space-in-code)
511-511: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
518-518: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
552-552: Spaces inside code span elements
(MD038, no-space-in-code)
560-560: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
567-567: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
567-567: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
578-578: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
585-585: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
585-585: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
594-594: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
602-602: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
602-602: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
610-610: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
610-610: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
617-617: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
617-617: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
634-634: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
634-634: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
670-670: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
682-682: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI Agents
In
@en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md:
- Line 275: Update the fenced code blocks listed to include appropriate language
identifiers for syntax highlighting: add ```bash (or similar) to the connection
string output block referenced at line 275 and the AWS output block at line 296;
add ```plaintext (or ```bash) to the JAAS config block at line 373; and add
```bash or ```plaintext to the output blocks at lines 567, 585, 602, 610, 617,
and 634 so each fenced block declares its language and enables proper
highlighting.
- Line 210: Replace the bold step header "**Step 3.1: Create a resource group**"
with a proper markdown heading using sentence case, e.g. "### Step 3.1: Create a
resource group", and apply the same conversion to the other bold step headers in
the file (the lines containing "**Step 3.2: ...**", "**Step 3.3: ...**", "**Step
3.4: ...**") so TOC generators and screen readers can parse them correctly.
- Line 441: Remove the extra spaces inside the inline code spans for the message
string literals: change occurrences like `` `[Reply Service] Received request:
${requestContent}` `` to ```[Reply Service] Received request:
${requestContent}``` (i.e., remove the space after the opening backtick so the
code span contains `string` instead of `` `string ` ``); apply the same fix for
the other affected inline code spans on the listed lines (the other message
literals at the same pattern on lines 449, 464, 505, and 552).
- Line 5: Convert all headers below Level 1 to sentence case; update each
occurrence of the specified header strings to the sentence-case variants (e.g.,
change "What You'll Learn" → "What you'll learn", "Architecture Overview" →
"Architecture overview", "Request-Reply Pattern" → "Request-reply pattern", "How
it Works" → "How it works", "Key Components" → "Key components", "In this
Example" → "In this example", "What You'll Build" → "What you'll build",
"Technology Stack" → "Technology stack", "Setting Up Azure Event Hub" → "Setting
up Azure Event Hub", "Step 4: Get Connection String" → "Step 4: Get connection
string", "Step 5: Verify Your Setup" → "Step 5: Verify your setup", "Building
the Reply Service" → "Building the reply service", "Step 5: Create the Response
Listener" → "Step 5: Create the response listener", "Running the Services" →
"Running the services", "Step 2: Start the Request Service" → "Step 2: Start the
request service", "Step 3: Send a Test Request" → "Step 3: Send a test request",
"Authentication Failed" → "Authentication failed", "No Messages Received" → "No
messages received", "Cleanup: Delete Azure Resources" → "Cleanup: Delete Azure
resources", "Option 1: Delete Using Azure CLI (Recommended)" → "Option 1: Delete
using Azure CLI (recommended)", and "Next Steps" → "Next steps"); locate and
edit these header lines in the markdown so only the first word and proper nouns
remain capitalized while preserving punctuation and numbering.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (12)
en/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/1-create-reply-service-project.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/2-create-kafka-producer-connection.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-2-create-kafka-event-handler.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-3-create-kafka-event-handler.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-create-kafka-event-handler.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/4-add-foreach-block.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/5-deserialize-request-message.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/6-log-request.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/7-create-response-variable.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/8-send-response.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/9-log-response.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/architecture-diagram.pngis excluded by!**/*.png
📒 Files selected for processing (1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-12T05:34:19.589Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 169
File: en/docs/deploy/deployment-best-practices/network-level-security.md:1-20
Timestamp: 2025-11-12T05:34:19.589Z
Learning: In the wso2/docs-bi repository documentation files, using h3 (###) subsection headings directly under h1 (#) titles is an intentional style choice, even though it violates standard markdown heading increment rules.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
🪛 markdownlint-cli2 (0.18.1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
68-68: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
69-69: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
160-160: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
170-170: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
176-176: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
190-190: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
202-202: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
210-210: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
212-212: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
218-218: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
220-220: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
228-228: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
230-230: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
238-238: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
240-240: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
250-250: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
263-263: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
275-275: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
275-275: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
286-286: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
296-296: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
296-296: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
373-373: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
373-373: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
441-441: Spaces inside code span elements
(MD038, no-space-in-code)
449-449: Spaces inside code span elements
(MD038, no-space-in-code)
456-456: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
464-464: Spaces inside code span elements
(MD038, no-space-in-code)
505-505: Spaces inside code span elements
(MD038, no-space-in-code)
511-511: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
518-518: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
552-552: Spaces inside code span elements
(MD038, no-space-in-code)
560-560: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
567-567: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
567-567: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
578-578: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
585-585: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
585-585: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
594-594: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
602-602: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
602-602: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
610-610: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
610-610: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
617-617: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
617-617: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
634-634: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
634-634: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
670-670: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
682-682: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
🔇 Additional comments (1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md (1)
68-69: Fix unordered list indentation.Lines 68–69 use 4 spaces for nested list items; should use 2 spaces per markdown convention.
- Publish-subscribe messaging patterns - - Apache Kafka concepts (topics, producers, consumers) + - Apache Kafka concepts (topics, producers, consumers)⛔ Skipped due to learnings
Learnt from: dulajdilshan Repo: wso2/docs-bi PR: 175 File: en/docs/deploy/deployment-best-practices/runtime-security.md:25-29 Timestamp: 2025-11-13T07:02:39.808Z Learning: In the wso2/docs-bi repository, nested list items should use 4-space indentation because MkDocs (Python-Markdown) requires 4 spaces for proper rendering. The markdownlint MD007 rule should be configured to accept 4-space indentation rather than the default 2 spaces.
| LOCATION="eastus" # Change to your preferred region | ||
| ``` | ||
|
|
||
| **Step 3.1: Create a resource group** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Convert bold step headers to markdown headings for accessibility.
Step headers using bold text (**Step X.Y: ...**) prevent proper document structure parsing by TOC generators and screen readers. Convert to ### headings and apply sentence case.
🔎 Proposed fixes for step headers
-**Step 3.1: Create a resource group**
+### Step 3.1: Create a resource group
-**Step 3.2: Create Event Hub namespace (Standard tier required for Kafka)**
+### Step 3.2: Create Event Hub namespace (standard tier required for Kafka)
-**Step 3.3: Create the 'requests' topic (Event Hub)**
+### Step 3.3: Create the 'requests' topic (Event Hub)
-**Step 3.4: Create the 'responses' topic (Event Hub)**
+### Step 3.4: Create the 'responses' topic (Event Hub)Apply the same fix to other bold step headers throughout the document (lines 218, 228, 238).
Also applies to: 218-218, 228-228, 238-238
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
210-210: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🤖 Prompt for AI Agents
In
@en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
around line 210, Replace the bold step header "**Step 3.1: Create a resource
group**" with a proper markdown heading using sentence case, e.g. "### Step 3.1:
Create a resource group", and apply the same conversion to the other bold step
headers in the file (the lines containing "**Step 3.2: ...**", "**Step 3.3:
...**", "**Step 3.4: ...**") so TOC generators and screen readers can parse them
correctly.
|
|
||
| This outputs the connection string: | ||
|
|
||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add language specifications to fenced code blocks.
Several code blocks lack language identifiers (e.g., ```bash, ```json), which disables syntax highlighting and impacts readability. Add appropriate language tags:
- Line 275: Connection string output →
```bashor similar - Line 296: AWS output →
```bash - Line 373: JAAS config format (critical) →
```plaintextor```bash - Lines 567, 585, 602, 610, 617, 634: Output blocks →
```bashor```plaintext
Also applies to: 296-296, 373-373, 567-567, 585-585, 602-602, 610-610, 617-617, 634-634
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
275-275: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
275-275: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
🤖 Prompt for AI Agents
In
@en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
around line 275, Update the fenced code blocks listed to include appropriate
language identifiers for syntax highlighting: add ```bash (or similar) to the
connection string output block referenced at line 275 and the AWS output block
at line 296; add ```plaintext (or ```bash) to the JAAS config block at line 373;
and add ```bash or ```plaintext to the output blocks at lines 567, 585, 602,
610, 617, and 634 so each fenced block declares its language and enables proper
highlighting.
|
|
||
| 3. **Log the Request** | ||
| - Click **+** → Search for `log` → Select `printInfo`. | ||
| - Message: `string `[Reply Service] Received request: ${requestContent}``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove spaces inside inline code spans.
Lines 441, 449, 464, 505, 552 have unnecessary spaces at code span boundaries:
- Remove space after opening backtick:
`string `→`string`
Example at line 441: `[Reply Service] Received request: ${requestContent}` (remove leading space).
Also applies to: 449-449, 464-464, 505-505, 552-552
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
441-441: Spaces inside code span elements
(MD038, no-space-in-code)
🤖 Prompt for AI Agents
In
@en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
around line 441, Remove the extra spaces inside the inline code spans for the
message string literals: change occurrences like `` `[Reply Service] Received
request: ${requestContent}` `` to ```[Reply Service] Received request:
${requestContent}``` (i.e., remove the space after the opening backtick so the
code span contains `string` instead of `` `string ` ``); apply the same fix for
the other affected inline code spans on the listed lines (the other message
literals at the same pattern on lines 449, 464, 505, and 552).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI Agents
In
@en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md:
- Around line 1-724: The document has lingering formatting issues: convert title
and major headings from Title Case to sentence case (e.g., change "# Kafka
Request-Reply Pattern with Azure Event Hub" and headings like "## What You'll
Learn", "### Step 1: Install Azure CLI" to sentence case); replace bolded step
headers (e.g., the "**Step 3.1: Create a resource group**" style) with proper
Markdown headings (use ###/#### as appropriate) rather than bold text; add
language identifiers to all fenced code blocks that are missing them (e.g., use
```bash, ```json, ```ballerina where applicable) and ensure inline code spans
use backticks with single spaces removed around code (fix instances like `
$ConnectionString ` → `$ConnectionString`), updating occurrences such as JAAS
config examples and configuration tables; review and normalize header casing and
inline code spacing across sections like "Setting Up Azure Event Hub", "Building
the Reply Service", and code examples that reference symbols like
`sasl.jaas.config`, `requestProducer`, `responseProducer`, `onConsumerRecord`,
and the JAAS config line to ensure consistency with WSO2 doc standards.
- Line 5: Convert all Markdown headers below the top-level header in
kafka-request-reply-pattern-with-azure-event-hub.md from Title Case to sentence
case (only capitalize the first word and proper nouns). Locate the headers
referenced in the review (occurrences at lines 12, 21, 25, 32, 46, 52, 71, 81,
259, 282, 333, 527, 556, 584, 592, 631, 650, 672, 676, 708) plus any other
non-Level-1 headers, and edit each header text to use sentence case while
preserving punctuation and Markdown header markers; do not change Level 1
heading(s) or alter header anchors/IDs beyond the text content. Ensure
consistency across the file after edits.
🧹 Nitpick comments (1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md (1)
497-499: Fix inconsistent list indentation.Line 499 has misaligned indentation relative to the surrounding list items at the same level. Ensure consistent spacing.
🔎 Proposed fix for list indentation
4. Add a resource: - Method: `POST` - Path: `/request` - - Payload: `string` + - Payload: `string`
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (23)
en/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/1-create-reply-service-project.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/10-create-request-service-project.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-2-create-http-service.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-create-http-service.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/12-log-request.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/13-send-to-kafka.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/14-return-response.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-2-create-response-listener.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-3-create-response-listener.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-4-create-response-listener.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-create-response-listener.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/16-log-received-response.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/2-create-kafka-producer-connection.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-2-create-kafka-event-handler.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-3-create-kafka-event-handler.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-create-kafka-event-handler.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/4-add-foreach-block.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/5-deserialize-request-message.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/6-log-request.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/7-create-response-variable.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/8-send-response.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/9-log-response.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/architecture-diagram.pngis excluded by!**/*.png
📒 Files selected for processing (1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-12T05:34:18.459Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 169
File: en/docs/deploy/deployment-best-practices/os-level-security.md:1-25
Timestamp: 2025-11-12T05:34:18.459Z
Learning: In the WSO2 docs-bi repository, specifically in deployment best practices documentation files under en/docs/deploy/deployment-best-practices/, using h3 (###) headings directly after h1 titles (instead of h2) is intentional and should not be flagged.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
📚 Learning: 2025-11-12T05:34:19.589Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 169
File: en/docs/deploy/deployment-best-practices/network-level-security.md:1-20
Timestamp: 2025-11-12T05:34:19.589Z
Learning: In the wso2/docs-bi repository documentation files, using h3 (###) subsection headings directly under h1 (#) titles is an intentional style choice, even though it violates standard markdown heading increment rules.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
📚 Learning: 2025-11-13T07:02:39.808Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 175
File: en/docs/deploy/deployment-best-practices/runtime-security.md:25-29
Timestamp: 2025-11-13T07:02:39.808Z
Learning: In the wso2/docs-bi repository, nested list items should use 4-space indentation because MkDocs (Python-Markdown) requires 4 spaces for proper rendering. The markdownlint MD007 rule should be configured to accept 4-space indentation rather than the default 2 spaces.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
🪛 markdownlint-cli2 (0.18.1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
68-68: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
69-69: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
160-160: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
170-170: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
176-176: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
190-190: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
202-202: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
210-210: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
212-212: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
218-218: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
220-220: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
228-228: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
230-230: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
238-238: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
240-240: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
250-250: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
263-263: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
275-275: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
275-275: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
286-286: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
296-296: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
296-296: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
373-373: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
373-373: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
441-441: Spaces inside code span elements
(MD038, no-space-in-code)
449-449: Spaces inside code span elements
(MD038, no-space-in-code)
456-456: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
464-464: Spaces inside code span elements
(MD038, no-space-in-code)
499-499: Inconsistent indentation for list items at the same level
Expected: 5; Actual: 4
(MD005, list-indent)
508-508: Spaces inside code span elements
(MD038, no-space-in-code)
514-514: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
521-521: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
562-562: Spaces inside code span elements
(MD038, no-space-in-code)
570-570: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
577-577: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
577-577: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
588-588: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
595-595: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
595-595: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
604-604: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
612-612: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
612-612: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
620-620: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
620-620: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
627-627: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
627-627: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
644-644: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
644-644: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
680-680: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
692-692: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
...tegration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
Show resolved
Hide resolved
|
|
||
| In this tutorial, you will learn how to build a simple request-reply messaging pattern using Azure Event Hub with the Kafka event handler and WSO2 Integrator: BI. You'll create two services that communicate bidirectionally through Event Hub topics. | ||
|
|
||
| ## What You'll Learn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Convert all headers below Level 1 to sentence case.
Multiple headers use Title Case instead of sentence case. This issue was flagged in previous reviews and remains unaddressed. Per WSO2 documentation standards, only the first word and proper nouns should be capitalized.
🔎 Proposed fixes for header case
-## What You'll Learn
+## What you'll learn
-## Architecture Overview
+## Architecture overview
-### Request-Reply Pattern
+### Request-reply pattern
-#### How it Works
+#### How it works
-#### Key Components
+#### Key components
-#### In this Example
+#### In this example
-## What You'll Build
+## What you'll build
-## Technology Stack
+## Technology stack
-## Setting Up Azure Event Hub
+## Setting up Azure Event Hub
-### Step 4: Get Connection String
+### Step 4: Get connection string
-### Step 5: Verify Your Setup
+### Step 5: Verify your setup
-## Building the Reply Service
+## Building the reply service
-### Step 5: Create the Response Listener
+### Step 5: Create the response listener
-## Running the Services
+## Running the services
-### Step 2: Start the Request Service
+### Step 2: Start the request service
-### Step 3: Send a Test Request
+### Step 3: Send a test request
-### Authentication Failed
+### Authentication failed
-### No Messages Received
+### No messages received
-## Cleanup: Delete Azure Resources
+## Cleanup: Delete Azure resources
-### Option 1: Delete Using Azure CLI (Recommended)
+### Option 1: Delete using Azure CLI (recommended)
-## Next Steps
+## Next stepsAlso applies to: 12-12, 21-21, 25-25, 32-32, 46-46, 52-52, 71-71, 81-81, 259-259, 282-282, 333-333, 527-527, 556-556, 584-584, 592-592, 631-631, 650-650, 672-672, 676-676, 708-708
🤖 Prompt for AI Agents
In
@en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
around line 5, Convert all Markdown headers below the top-level header in
kafka-request-reply-pattern-with-azure-event-hub.md from Title Case to sentence
case (only capitalize the first word and proper nouns). Locate the headers
referenced in the review (occurrences at lines 12, 21, 25, 32, 46, 52, 71, 81,
259, 282, 333, 527, 556, 584, 592, 631, 650, 672, 676, 708) plus any other
non-Level-1 headers, and edit each header text to use sentence case while
preserving punctuation and Markdown header markers; do not change Level 1
heading(s) or alter header anchors/IDs beyond the text content. Ensure
consistency across the file after edits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md (1)
1-1: Consider simplifying the filename for clarity.Per a previous review comment, the filename could be more concise. Current:
kafka-request-reply-pattern-with-azure-event-hub.md. Since the file already resides in/kafka/, the "kafka-" prefix is somewhat redundant. Consider shortening torequest-reply-pattern-with-azure-event-hub.mdor similar for improved clarity and consistency with other documentation.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (23)
en/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/1-create-reply-service-project.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/10-create-request-service-project.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-2-create-http-service.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-create-http-service.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/12-log-request.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/13-send-to-kafka.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/14-return-response.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-2-create-response-listener.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-3-create-response-listener.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-4-create-response-listener.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-create-response-listener.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/16-log-received-response.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/2-create-kafka-producer-connection.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-2-create-kafka-event-handler.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-3-create-kafka-event-handler.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-create-kafka-event-handler.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/4-add-foreach-block.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/5-deserialize-request-message.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/6-log-request.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/7-create-response-variable.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/8-send-response.gifis excluded by!**/*.gifen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/9-log-response.pngis excluded by!**/*.pngen/docs/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/architecture-diagram.pngis excluded by!**/*.png
📒 Files selected for processing (1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-12T05:34:19.589Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 169
File: en/docs/deploy/deployment-best-practices/network-level-security.md:1-20
Timestamp: 2025-11-12T05:34:19.589Z
Learning: In the wso2/docs-bi repository documentation files, using h3 (###) subsection headings directly under h1 (#) titles is an intentional style choice, even though it violates standard markdown heading increment rules.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
📚 Learning: 2025-11-12T05:34:18.459Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 169
File: en/docs/deploy/deployment-best-practices/os-level-security.md:1-25
Timestamp: 2025-11-12T05:34:18.459Z
Learning: In the WSO2 docs-bi repository, specifically in deployment best practices documentation files under en/docs/deploy/deployment-best-practices/, using h3 (###) headings directly after h1 titles (instead of h2) is intentional and should not be flagged.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
📚 Learning: 2025-11-13T07:02:39.808Z
Learnt from: dulajdilshan
Repo: wso2/docs-bi PR: 175
File: en/docs/deploy/deployment-best-practices/runtime-security.md:25-29
Timestamp: 2025-11-13T07:02:39.808Z
Learning: In the wso2/docs-bi repository, nested list items should use 4-space indentation because MkDocs (Python-Markdown) requires 4 spaces for proper rendering. The markdownlint MD007 rule should be configured to accept 4-space indentation rather than the default 2 spaces.
Applied to files:
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
🪛 markdownlint-cli2 (0.18.1)
en/docs/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub.md
68-68: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
69-69: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
160-160: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
170-170: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
176-176: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
190-190: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
202-202: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
210-210: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
212-212: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
218-218: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
220-220: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
228-228: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
230-230: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
238-238: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
240-240: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
250-250: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
263-263: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
275-275: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
275-275: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
286-286: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
296-296: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
296-296: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
373-373: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
373-373: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
441-441: Spaces inside code span elements
(MD038, no-space-in-code)
449-449: Spaces inside code span elements
(MD038, no-space-in-code)
456-456: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
464-464: Spaces inside code span elements
(MD038, no-space-in-code)
499-499: Inconsistent indentation for list items at the same level
Expected: 5; Actual: 4
(MD005, list-indent)
508-508: Spaces inside code span elements
(MD038, no-space-in-code)
514-514: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
521-521: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
562-562: Spaces inside code span elements
(MD038, no-space-in-code)
570-570: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
577-577: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
577-577: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
588-588: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
595-595: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
595-595: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
604-604: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
612-612: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
612-612: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
620-620: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
620-620: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
627-627: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
627-627: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
644-644: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
644-644: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
680-680: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
692-692: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
| ## What You'll Learn | ||
|
|
||
| - Configure Azure Event Hub as a Kafka-compatible message broker | ||
| - Create a Request Service that publishes messages and listens for responses | ||
| - Build a Reply Service that consumes requests and sends back responses | ||
| - Implement the request-reply pattern using two Event Hub topics | ||
|
|
||
| ## Architecture Overview | ||
|
|
||
| The system consists of two services communicating through Azure Event Hub: | ||
|
|
||
| - **Request Service**: Exposes an HTTP endpoint to trigger requests, sends messages to the requests topic, and listens on the responses topic for replies. | ||
| - **Reply Service**: Listens on the requests topic, processes incoming messages, and publishes responses to the responses topic. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/architecture-diagram.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/architecture-diagram.png" alt="Architecture Diagram" width="70%"></a> | ||
|
|
||
| ### Request-Reply Pattern | ||
|
|
||
| The Request-Reply pattern is a messaging pattern where a requestor sends a message and expects a correlated response from a replier. | ||
|
|
||
| #### How it Works | ||
|
|
||
| 1. Requestor sends a message to a REQUEST channel (topic) | ||
| 2. Replier consumes the message, processes it, and sends a response | ||
| 3. Replier publishes the response to a REPLY channel (topic) | ||
| 4. Requestor consumes the response from the reply channel | ||
|
|
||
| #### Key Components | ||
|
|
||
| - **Request Channel**: Topic where requests are published (e.g., "requests") | ||
| - **Reply Channel**: Topic where responses are published (e.g., "responses") | ||
| - **Requestor**: Service that initiates the request and awaits response | ||
| - **Replier**: Service that processes requests and sends responses | ||
|
|
||
| #### Advantages | ||
|
|
||
| - Decouples sender and receiver | ||
| - Asynchronous communication | ||
| - Scalable (multiple repliers can process requests) | ||
| - Fault tolerant (messages persist in the broker) | ||
|
|
||
| #### In this Example | ||
|
|
||
| - **Request Service**: Exposes HTTP endpoint, publishes to "requests", listens on "responses" | ||
| - **Reply Service**: Listens on "requests", processes messages, publishes to "responses" | ||
| - **Broker**: Azure Event Hub (Kafka-compatible) | ||
|
|
||
| ## What You'll Build | ||
|
|
||
| By the end of this tutorial, you'll have: | ||
|
|
||
| - A Request Service with an HTTP endpoint and Kafka listener | ||
| - A Reply Service with event-driven message processing | ||
| - Secure communication with Azure Event Hub using SASL_SSL | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Before starting this tutorial, ensure you have: | ||
|
|
||
| - VS Code with WSO2 Integrator: BI and Ballerina plugins installed | ||
| - Azure account with an active subscription ([create free account](https://azure.microsoft.com/free/)) | ||
| - Azure CLI installed (installation instructions below) | ||
| - Basic understanding of: | ||
| - Publish-subscribe messaging patterns | ||
| - Apache Kafka concepts (topics, producers, consumers) | ||
|
|
||
| ## Technology Stack | ||
|
|
||
| | Component | Technology | Purpose | | ||
| |-----------|------------|---------| | ||
| | Platform | WSO2 Integrator: BI | Service implementation | | ||
| | Message Broker | Azure Event Hub | Kafka-compatible event streaming | | ||
| | Protocol | Kafka | Message publishing and consumption | | ||
| | Security | SASL_SSL | Authentication with connection string | | ||
| | CLI Tool | Azure CLI | Azure resource management | | ||
|
|
||
| ## Setting Up Azure Event Hub | ||
|
|
||
| We'll use the Azure CLI to set up the Event Hub infrastructure. This approach is faster, reproducible, and easier than using the portal. | ||
|
|
||
| ### Step 1: Install Azure CLI | ||
|
|
||
| Choose your operating system and follow the installation steps: | ||
|
|
||
| === "macOS" | ||
|
|
||
| **Option A: Using Homebrew (Recommended)** | ||
|
|
||
| ```bash | ||
| brew update && brew install azure-cli | ||
| ``` | ||
|
|
||
| **Option B: Using the install script** | ||
|
|
||
| ```bash | ||
| curl -L https://aka.ms/InstallAzureCli | bash | ||
| ``` | ||
|
|
||
| === "Windows" | ||
|
|
||
| **Option A: Using winget (Windows 11/10)** | ||
|
|
||
| ```bash | ||
| winget install -e --id Microsoft.AzureCLI | ||
| ``` | ||
|
|
||
| **Option B: Using MSI installer** | ||
|
|
||
| Download and run the MSI installer from: [https://aka.ms/installazurecliwindows](https://aka.ms/installazurecliwindows) | ||
|
|
||
| **Option C: Using Chocolatey** | ||
|
|
||
| ```bash | ||
| choco install azure-cli | ||
| ``` | ||
|
|
||
| === "Linux (Ubuntu/Debian)" | ||
|
|
||
| ```bash | ||
| # Install dependencies | ||
| sudo apt-get update | ||
| sudo apt-get install ca-certificates curl apt-transport-https lsb-release gnupg | ||
|
|
||
| # Download and install the Microsoft signing key | ||
| sudo mkdir -p /etc/apt/keyrings | ||
| curl -sLS https://packages.microsoft.com/keys/microsoft.asc | \ | ||
| gpg --dearmor | \ | ||
| sudo tee /etc/apt/keyrings/microsoft.gpg > /dev/null | ||
| sudo chmod go+r /etc/apt/keyrings/microsoft.gpg | ||
|
|
||
| # Add the Azure CLI repository | ||
| AZ_DIST=$(lsb_release -cs) | ||
| echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $AZ_DIST main" | \ | ||
| sudo tee /etc/apt/sources.list.d/azure-cli.list | ||
|
|
||
| # Install Azure CLI | ||
| sudo apt-get update | ||
| sudo apt-get install azure-cli | ||
| ``` | ||
|
|
||
| === "Linux (RHEL/CentOS/Fedora)" | ||
|
|
||
| ```bash | ||
| # Import the Microsoft repository key | ||
| sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc | ||
|
|
||
| # Add the Azure CLI repository | ||
| sudo dnf install -y https://packages.microsoft.com/config/rhel/9.0/packages-microsoft-prod.rpm | ||
|
|
||
| # Install Azure CLI | ||
| sudo dnf install azure-cli | ||
| ``` | ||
|
|
||
| After installation, verify Azure CLI is working: | ||
|
|
||
| ```bash | ||
| az --version | ||
| ``` | ||
|
|
||
| You should see output showing the Azure CLI version (2.50.0 or higher recommended). | ||
|
|
||
| ### Step 2: Login to Azure | ||
|
|
||
| Open a terminal and authenticate with your Azure account: | ||
|
|
||
| ```bash | ||
| az login | ||
| ``` | ||
|
|
||
| This opens a browser window for authentication. After signing in, you'll see your subscription details in the terminal: | ||
|
|
||
| ```json | ||
| [ | ||
| { | ||
| "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", | ||
| "isDefault": true, | ||
| "name": "Your Subscription Name", | ||
| "state": "Enabled", | ||
| "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | ||
| } | ||
| ] | ||
| ``` | ||
|
|
||
| If you have multiple subscriptions, set the one you want to use: | ||
|
|
||
| ```bash | ||
| # List all subscriptions | ||
| az account list --output table | ||
|
|
||
| # Set a specific subscription | ||
| az account set --subscription "Your Subscription Name" | ||
| ``` | ||
|
|
||
| ### Step 3: Create Azure Resources | ||
|
|
||
| Run these commands to create all required Azure resources: | ||
|
|
||
| ```bash | ||
| # Set configuration variables | ||
| # IMPORTANT: Change NAMESPACE to something unique (e.g., add your initials) | ||
| RESOURCE_GROUP="kafka-eventhub-demo-rg" | ||
| NAMESPACE="kafka-eventhub-demo" # Must be globally unique! | ||
| LOCATION="eastus" # Change to your preferred region | ||
| ``` | ||
|
|
||
| **Step 3.1: Create a resource group** | ||
|
|
||
| ```bash | ||
| az group create \ | ||
| --name $RESOURCE_GROUP \ | ||
| --location $LOCATION | ||
| ``` | ||
|
|
||
| **Step 3.2: Create Event Hub namespace (Standard tier required for Kafka)** | ||
|
|
||
| ```bash | ||
| az eventhubs namespace create \ | ||
| --name $NAMESPACE \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --location $LOCATION \ | ||
| --sku Standard | ||
| ``` | ||
|
|
||
| **Step 3.3: Create the 'requests' topic (Event Hub)** | ||
|
|
||
| ```bash | ||
| az eventhubs eventhub create \ | ||
| --name requests \ | ||
| --namespace-name $NAMESPACE \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --partition-count 1 | ||
| ``` | ||
|
|
||
| **Step 3.4: Create the 'responses' topic (Event Hub)** | ||
|
|
||
| ```bash | ||
| az eventhubs eventhub create \ | ||
| --name responses \ | ||
| --namespace-name $NAMESPACE \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --partition-count 1 | ||
| ``` | ||
|
|
||
| Expected output after each command: | ||
|
|
||
| ```json | ||
| { | ||
| "id": "/subscriptions/.../resourceGroups/kafka-eventhub-demo-rg/...", | ||
| "name": "requests", | ||
| "status": "Active", | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| ### Step 4: Get Connection String | ||
|
|
||
| Retrieve the connection string needed for your WSO2 Integrator: BI services: | ||
|
|
||
| ```bash | ||
| # Get the primary connection string | ||
| az eventhubs namespace authorization-rule keys list \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --namespace-name $NAMESPACE \ | ||
| --name RootManageSharedAccessKey \ | ||
| --query primaryConnectionString \ | ||
| --output tsv | ||
| ``` | ||
|
|
||
| This outputs the connection string: | ||
|
|
||
| ``` | ||
| Endpoint=sb://kafka-eventhub-demo.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=abc123… | ||
| ``` | ||
|
|
||
| !!! important | ||
| Save this connection string (starting from `Endpoint`, not `sb://`). You'll need it for the Ballerina configuration. | ||
|
|
||
| ### Step 5: Verify Your Setup | ||
|
|
||
| Confirm that your Event Hub namespace and topics were created: | ||
|
|
||
| ```bash | ||
| # List Event Hubs (topics) in your namespace | ||
| az eventhubs eventhub list \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --namespace-name $NAMESPACE \ | ||
| --output table | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ``` | ||
| Name Status PartitionCount | ||
| --------- -------- ---------------- | ||
| requests Active 1 | ||
| responses Active 1 | ||
| ``` | ||
|
|
||
| ### Step 6: Note Your Configuration Values | ||
|
|
||
| Based on the resources you created, your configuration values are: | ||
|
|
||
| | Setting | Value | | ||
| |---------|-------| | ||
| | Bootstrap Server | `<namespace>.servicebus.windows.net:9093` | | ||
| | Security Protocol | `SASL_SSL` | | ||
| | SASL Mechanism | `PLAIN` | | ||
| | Username | `$ConnectionString` (literal string) | | ||
| | Password | Your full connection string from Step 4 | | ||
|
|
||
| For example, if your namespace is `kafka-eventhub-demo`: | ||
|
|
||
| - Bootstrap Server: `kafka-eventhub-demo.servicebus.windows.net:9093` | ||
|
|
||
| ### Alternative: Using Azure Portal (GUI) | ||
|
|
||
| If you prefer a graphical interface, you can create the same resources through the Azure Portal: | ||
|
|
||
| 1. Go to [Azure Portal](https://portal.azure.com) | ||
| 2. Click **Create a resource** → Search for **Event Hubs** → Click **Create** | ||
| 3. Fill in: | ||
| - Resource group: Create new → `kafka-eventhub-demo-rg` | ||
| - Namespace name: `kafka-eventhub-demo` (must be unique) | ||
| - Pricing tier: **Standard** (Basic doesn't support Kafka) | ||
| 4. Click **Review + create** → **Create** | ||
| 5. After deployment, go to the namespace → **Event Hubs** → Create `requests` and `responses` | ||
| 6. Go to **Shared access policies** → **RootManageSharedAccessKey** → Copy connection string | ||
|
|
||
| ## Building the Reply Service | ||
|
|
||
| The Reply Service listens for incoming requests and sends back responses. We build this first so it's ready when the Request Service starts. | ||
|
|
||
| ### Step 1: Create a new integration project | ||
|
|
||
| 1. Open VS Code with WSO2 Integrator: BI installed. | ||
| 2. Click on the **BI** icon on the sidebar. | ||
| 3. Click on the **Create New Integration** button. | ||
| 4. Enter the project name as `ReplyService`. | ||
| 5. Select project directory and click on the **Create Integration** button. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/1-create-reply-service-project.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/1-create-reply-service-project.gif" alt="Create Reply Service Project" width="70%"></a> | ||
|
|
||
| ### Step 2: Create the Kafka Producer connection | ||
|
|
||
| The producer sends response messages back to the Request Service. | ||
|
|
||
| !!! important | ||
| Azure Event Hub requires a specific JAAS configuration format. We'll use `additionalProperties` to pass the SASL configuration directly. | ||
|
|
||
| 1. Click **+** next to **Connections** in the left panel. | ||
| 2. Select **Kafka Producer** under the Messaging category. | ||
| 3. Configure the connection: | ||
|
|
||
| | Setting | Value | | ||
| |---------|-------| | ||
| | Name | `responseProducer` | | ||
| | Bootstrap Servers | `<namespace>.servicebus.windows.net:9093` | | ||
| | Security Protocol | `kafka:PROTOCOL_SASL_SSL` | | ||
|
|
||
| 4. For `additionalProperties`, add these key-value pairs: | ||
|
|
||
| | Key | Value | | ||
| |-----|-------| | ||
| | `sasl.mechanism` | `PLAIN` | | ||
| | `sasl.jaas.config` | (see JAAS config format below) | | ||
|
|
||
| **JAAS Config Format:** | ||
|
|
||
| ``` | ||
| org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password="<your-connection-string>"; | ||
| ``` | ||
|
|
||
| 5. Click **Save**. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/2-create-kafka-producer-connection.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/2-create-kafka-producer-connection.png" alt="Create Kafka Producer Connection" width="70%"></a> | ||
|
|
||
| ### Step 3: Create the Kafka Event Handler | ||
|
|
||
| 1. Click **+** next to **Entry Points**. | ||
| 2. Select **Kafka Event Integration**. | ||
| 3. Configure: | ||
|
|
||
| | Setting | Value | | ||
| |---------|-------| | ||
| | Bootstrap Servers | `<namespace>.servicebus.windows.net:9093` | | ||
| | Topic | `requests` | | ||
|
|
||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-create-kafka-event-handler.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-create-kafka-event-handler.gif" alt="Create Kafka Event Handler" width="70%"></a> | ||
|
|
||
| 4. Click **Save**, then **Configure** to add consumer settings: | ||
|
|
||
| | Setting | Value | | ||
| |---------|-------| | ||
| | groupId | `reply-service-group` | | ||
| | offsetReset | `kafka:OFFSET_RESET_LATEST` | | ||
| | securityProtocol | `kafka:PROTOCOL_SASL_SSL` | | ||
| | requestTimeout | `60` | | ||
| | sessionTimeout | `30` | | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-2-create-kafka-event-handler.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-2-create-kafka-event-handler.png" alt="Create Kafka Event Handler" width="70%"></a> | ||
|
|
||
| 5. For `additionalProperties`, add the same SASL configuration: | ||
|
|
||
| | Key | Value | | ||
| |-----|-------| | ||
| | `sasl.mechanism` | `PLAIN` | | ||
| | `sasl.jaas.config` | (same JAAS config as producer) | | ||
|
|
||
| 6. Click **+ Add Handler** and select `onConsumerRecord` with `kafka:BytesConsumerRecord`. | ||
| 7. Click **Save** to open the flow diagram. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-3-create-kafka-event-handler.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-3-create-kafka-event-handler.png" alt="Create Kafka Event Handler" width="70%"></a> | ||
|
|
||
| ### Step 4: Implement the Reply Logic | ||
|
|
||
| In the `onConsumerRecord` flow: | ||
|
|
||
| 1. **Add a ForEach Block** | ||
| - Click **+** → Select **ForEach** under Control. | ||
| - Collection: `messages` (from inputs). | ||
| - Variable Name: `message`. | ||
| - Variable Type: `kafka:BytesConsumerRecord`. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/4-add-foreach-block.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/4-add-foreach-block.gif" alt="Add ForEach Block" width="70%"></a> | ||
|
|
||
| 2. **Deserialize the Request Message** | ||
| - Click **+** → Select function `fromBytes`. | ||
| - Name: `requestContent`. | ||
| - Type: `string`. | ||
| - Expression: `message.value.value`. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/5-deserialize-request-message.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/5-deserialize-request-message.gif" alt="Deserialize Request Message" width="70%"></a> | ||
|
|
||
| 3. **Log the Request** | ||
| - Click **+** → Search for `log` → Select `printInfo`. | ||
| - Message: `string `[Reply Service] Received request: ${requestContent}``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/6-log-request.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/6-log-request.gif" alt="Log the Request" width="70%"></a> | ||
|
|
||
| 4. **Create the Response** | ||
| - Click **+** → Select **Declare variable**. | ||
| - Name: `responseContent`. | ||
| - Type: `string`. | ||
| - Expression: `string `Response to: "${requestContent}" | Status: OK``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/7-create-response-variable.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/7-create-response-variable.gif" alt="Create Response Variable" width="70%"></a> | ||
|
|
||
| 5. **Send the Response** | ||
| - Click **+** → Select `responseProducer` → Choose `send`. | ||
| - Create a new `BytesProducerRecord` value: | ||
| ```ballerina | ||
| { topic: "responses", value: responseContent.toBytes() } | ||
| ``` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/8-send-response.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/8-send-response.gif" alt="Send Response" width="70%"></a> | ||
|
|
||
| 6. **Log the Response** | ||
| - Click **+** → Select `printInfo`. | ||
| - Message: `string `[Reply Service] Sent response: ${responseContent}``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/9-log-response.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/9-log-response.gif" alt="Log Response" width="70%"></a> | ||
|
|
||
| ## Building the Request Service | ||
|
|
||
| The Request Service exposes an HTTP endpoint to trigger requests and listens for responses. | ||
|
|
||
| ### Step 1: Create a new integration project | ||
|
|
||
| Create a new integration named `RequestService` following the same steps as for the Reply Service. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/10-create-request-service-project.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/10-create-request-service-project.gif" alt="Create Request Service Project" width="70%"></a> | ||
|
|
||
| ### Step 2: Create the Kafka Producer connection | ||
|
|
||
| 1. Add a Kafka Producer connection named `requestProducer`. | ||
| 2. Configure with the same settings as Reply Service: | ||
| - Bootstrap Servers: `<namespace>.servicebus.windows.net:9093` | ||
| - Security Protocol: `kafka:PROTOCOL_SASL_SSL` | ||
| - `additionalProperties` with `sasl.mechanism` and `sasl.jaas.config` | ||
|
|
||
| ### Step 3: Create the HTTP Service | ||
|
|
||
| 1. Click **+** next to **Entry Points**. | ||
| 2. Select **HTTP Service**. | ||
| 3. Configure: | ||
| - Path: `/api` | ||
| - Port: `8080` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-create-http-service.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-create-http-service.gif" alt="Create HTTP Service" width="70%"></a> | ||
|
|
||
| 4. Add a resource: | ||
| - Method: `POST` | ||
| - Path: `/request` | ||
| - Payload: `string` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-2-create-http-service.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-2-create-http-service.gif" alt="Create HTTP Service" width="70%"></a> | ||
|
|
||
| ### Step 4: Implement the Request Logic | ||
|
|
||
| In the HTTP `POST /request` resource flow: | ||
|
|
||
| 1. **Log the Request** | ||
| - Add `printInfo`: `string `[Request Service] Sending request: ${payload}``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/12-log-request.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/12-log-request.png" alt="Log Request" width="70%"></a> | ||
|
|
||
| 2. **Send to Kafka** | ||
| - Call `requestProducer->send`: | ||
| ```ballerina | ||
| { topic: "requests", value: payload.toBytes() } | ||
| ``` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/13-send-to-kafka.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/13-send-to-kafka.gif" alt="Send to Kafka" width="70%"></a> | ||
|
|
||
| 3. **Return Response** | ||
| ```ballerina | ||
| string `Request sent successfully: ${payload}` | ||
| ``` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/14-return-response.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/14-return-response.gif" alt="Return Response" width="70%"></a> | ||
|
|
||
| ### Step 5: Create the Response Listener | ||
|
|
||
| 1. Add a **Kafka Event Integration** entry point. | ||
| 2. Configure: | ||
| - Topic: `responses` | ||
| - Group ID: `request-service-group` | ||
| - Security Protocol: `kafka:PROTOCOL_SASL_SSL` | ||
| - `additionalProperties` with `sasl.mechanism` and `sasl.jaas.config` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-create-response-listener.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-create-response-listener.gif" alt="Create Response Listener" width="70%"></a> | ||
|
|
||
| 3. Click **+ Add Handler** and select `onConsumerRecord` with `kafka:BytesConsumerRecord`. | ||
| 4. Click **Save** to open the flow diagram. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-2-create-response-listener.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-2-create-response-listener.gif" alt="Create Response Listener" width="70%"></a> | ||
|
|
||
| In the `onConsumerRecord` flow: | ||
|
|
||
| 1. **Add a ForEach Block** | ||
| - Click **+** → Select **ForEach** under Control. | ||
| - Collection: `messages` (from inputs). | ||
| - Variable Name: `message`. | ||
| - Variable Type: `kafka:BytesConsumerRecord`. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-3-create-response-listener.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-3-create-response-listener.gif" alt="Create Response Listener" width="70%"></a> | ||
|
|
||
| 2. **Deserialize the Response Message** | ||
| - Click **+** → Select function `fromBytes`. | ||
| - Name: `responseContent`. | ||
| - Type: `string`. | ||
| - Expression: `message.value.value`. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-4-create-response-listener.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-4-create-response-listener.gif" alt="Create Response Listener" width="70%"></a> | ||
|
|
||
| 3. **Log the Response** | ||
| - Message: `string `[Request Service] Received response: ${responseContent}``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/16-log-received-response.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/16-log-received-response.png" alt="Log Received Response" width="70%"></a> | ||
|
|
||
| ## Running the Services | ||
|
|
||
| ### Step 1: Start the Reply Service | ||
|
|
||
| ```bash | ||
| cd ReplyService | ||
| bal run | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ``` | ||
| Compiling source | ||
| wso2/reply_service:0.1.0 | ||
|
|
||
| Running executable | ||
| ``` | ||
|
|
||
| ### Step 2: Start the Request Service | ||
|
|
||
| In a new terminal: | ||
|
|
||
| ```bash | ||
| cd RequestService | ||
| bal run | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ``` | ||
| Compiling source | ||
| wso2/request_service:0.1.0 | ||
|
|
||
| Running executable | ||
| ``` | ||
|
|
||
| ### Step 3: Send a Test Request | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:8080/api/request \ | ||
| -H "Content-Type: text/plain" \ | ||
| -d "Hello Azure Event Hub" | ||
| ``` | ||
|
|
||
| Response: | ||
|
|
||
| ``` | ||
| Request sent: Hello Azure Event Hub | ||
| ``` | ||
|
|
||
| ### Step 4: Verify the Logs | ||
|
|
||
| **Request Service logs:** | ||
|
|
||
| ``` | ||
| [Request Service] Sending request: Hello Azure Event Hub | ||
| [Request Service] Received response: Response to: "Hello Azure Event Hub" | Status: OK | ||
| ``` | ||
|
|
||
| **Reply Service logs:** | ||
|
|
||
| ``` | ||
| [Reply Service] Received request: Hello Azure Event Hub | ||
| [Reply Service] Sent response: Response to: "Hello Azure Event Hub" | Status: OK | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Connection Timeout / Topic Not Found in Metadata | ||
|
|
||
| - Use `additionalProperties`: Azure Event Hub requires SASL configuration via `additionalProperties` with `sasl.mechanism` and `sasl.jaas.config` | ||
| - Verify your namespace name is correct | ||
| - Ensure port 9093 is not blocked by firewall | ||
| - Check the connection string is complete | ||
|
|
||
| ### Authentication Failed | ||
|
|
||
| - Verify the JAAS config format is exactly: | ||
| ``` | ||
| org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password="<connection-string>"; | ||
| ``` | ||
| - The `$ConnectionString` must be a literal string (not a variable) | ||
| - The password must be your complete connection string starting with `Endpoint=sb://...` | ||
|
|
||
| ### No Messages Received | ||
|
|
||
| - Ensure both topics exist in Azure | ||
| - Check consumer group IDs are different for each service | ||
| - Verify `offsetReset` is set to `LATEST` for new consumers | ||
|
|
||
| ## Summary | ||
|
|
||
| You have successfully built a request-reply messaging system using: | ||
|
|
||
| - Azure Event Hub as a Kafka-compatible message broker | ||
| - Two topics (`requests` and `responses`) for bidirectional communication | ||
| - SASL_SSL authentication with Azure connection strings | ||
| - Event-driven Kafka listeners for consuming messages | ||
| - HTTP endpoint for triggering requests | ||
|
|
||
| This pattern is useful for: | ||
|
|
||
| - Asynchronous request-response workflows | ||
| - Decoupling services while maintaining communication | ||
| - Building scalable microservices architectures | ||
|
|
||
| ## Cleanup: Delete Azure Resources | ||
|
|
||
| When you're done with this tutorial, delete the Azure resources to avoid ongoing charges. | ||
|
|
||
| ### Option 1: Delete Using Azure CLI (Recommended) | ||
|
|
||
| This single command deletes the resource group and everything in it: | ||
|
|
||
| ```bash | ||
| # Delete the resource group (includes namespace and all Event Hubs) | ||
| az group delete \ | ||
| --name kafka-eventhub-demo-rg \ | ||
| --yes \ | ||
| --no-wait | ||
| ``` | ||
|
|
||
| The `--no-wait` flag returns immediately while deletion continues in the background. | ||
|
|
||
| To verify deletion: | ||
|
|
||
| ```bash | ||
| # Check if resource group still exists | ||
| az group show --name kafka-eventhub-demo-rg | ||
| ``` | ||
|
|
||
| You should see: `Resource group 'kafka-eventhub-demo-rg' could not be found.` | ||
|
|
||
| ### Option 2: Delete Using Azure Portal | ||
|
|
||
| 1. Go to [Azure Portal](https://portal.azure.com) | ||
| 2. Search for **Resource groups** in the top search bar | ||
| 3. Click on `kafka-eventhub-demo-rg` | ||
| 4. Click **Delete resource group** | ||
| 5. Type the resource group name to confirm | ||
| 6. Click **Delete** | ||
|
|
||
| ### Cost Information | ||
|
|
||
| Azure Event Hub Standard tier costs approximately: | ||
|
|
||
| - Base cost: ~$22/month for the namespace | ||
| - Throughput units: Additional charges based on usage | ||
| - Ingress/egress: Small charges for data transfer | ||
|
|
||
| Deleting the resource group stops all charges immediately. | ||
|
|
||
| ## Next Steps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Convert all headers below Level 1 to sentence case per WSO2 documentation standards.
Multiple headers throughout the document use Title Case instead of sentence case. Past reviews flagged this issue, and it remains unaddressed. Per WSO2 documentation conventions, only the first word and proper nouns should be capitalized in headers below the h1 level.
🔎 Proposed fixes for header casing
-## What You'll Learn
+## What you'll learn
-## Architecture Overview
+## Architecture overview
-### Request-Reply Pattern
+### Request-reply pattern
-#### How it Works
+#### How it works
-#### Key Components
+#### Key components
-#### In this Example
+#### In this example
-## What You'll Build
+## What you'll build
-## Technology Stack
+## Technology stack
-## Setting Up Azure Event Hub
+## Setting up Azure Event Hub
-### Step 1: Install Azure CLI
+### Step 1: Install Azure CLI
-### Step 2: Login to Azure
+### Step 2: Login to Azure
-### Step 3: Create Azure Resources
+### Step 3: Create Azure resources
-### Step 4: Get Connection String
+### Step 4: Get connection string
-### Step 5: Verify Your Setup
+### Step 5: Verify your setup
-### Step 6: Note Your Configuration Values
+### Step 6: Note your configuration values
-## Building the Reply Service
+## Building the reply service
-### Step 5: Create the Response Listener
+### Step 5: Create the response listener
-## Running the Services
+## Running the services
-### Step 2: Start the Request Service
+### Step 2: Start the request service
-### Step 3: Send a Test Request
+### Step 3: Send a test request
-## Troubleshooting
+## Troubleshooting
-### Authentication Failed
+### Authentication failed
-### No Messages Received
+### No messages received
-## Cleanup: Delete Azure Resources
+## Cleanup: Delete Azure resources
-### Option 1: Delete Using Azure CLI (Recommended)
+### Option 1: Delete using Azure CLI (recommended)
-### Cost Information
+### Cost information
-## Next Steps
+## Next stepsNote: Proper nouns like "Azure CLI" and "Event Hub" retain capitalization; service names remain unchanged.
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
68-68: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
69-69: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
160-160: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
170-170: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
176-176: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
190-190: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
202-202: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
210-210: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
212-212: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
218-218: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
220-220: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
228-228: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
230-230: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
238-238: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
240-240: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
250-250: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
263-263: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
275-275: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
275-275: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
286-286: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
296-296: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
296-296: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
373-373: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
373-373: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
441-441: Spaces inside code span elements
(MD038, no-space-in-code)
449-449: Spaces inside code span elements
(MD038, no-space-in-code)
456-456: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
464-464: Spaces inside code span elements
(MD038, no-space-in-code)
499-499: Inconsistent indentation for list items at the same level
Expected: 5; Actual: 4
(MD005, list-indent)
508-508: Spaces inside code span elements
(MD038, no-space-in-code)
514-514: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
521-521: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
562-562: Spaces inside code span elements
(MD038, no-space-in-code)
570-570: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
577-577: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
577-577: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
588-588: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
595-595: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
595-595: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
604-604: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
612-612: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
612-612: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
620-620: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
620-620: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
627-627: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
627-627: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
644-644: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
644-644: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
680-680: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
692-692: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
| ```bash | ||
| az --version | ||
| ``` | ||
|
|
||
| You should see output showing the Azure CLI version (2.50.0 or higher recommended). | ||
|
|
||
| ### Step 2: Login to Azure | ||
|
|
||
| Open a terminal and authenticate with your Azure account: | ||
|
|
||
| ```bash | ||
| az login | ||
| ``` | ||
|
|
||
| This opens a browser window for authentication. After signing in, you'll see your subscription details in the terminal: | ||
|
|
||
| ```json | ||
| [ | ||
| { | ||
| "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", | ||
| "isDefault": true, | ||
| "name": "Your Subscription Name", | ||
| "state": "Enabled", | ||
| "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | ||
| } | ||
| ] | ||
| ``` | ||
|
|
||
| If you have multiple subscriptions, set the one you want to use: | ||
|
|
||
| ```bash | ||
| # List all subscriptions | ||
| az account list --output table | ||
|
|
||
| # Set a specific subscription | ||
| az account set --subscription "Your Subscription Name" | ||
| ``` | ||
|
|
||
| ### Step 3: Create Azure Resources | ||
|
|
||
| Run these commands to create all required Azure resources: | ||
|
|
||
| ```bash | ||
| # Set configuration variables | ||
| # IMPORTANT: Change NAMESPACE to something unique (e.g., add your initials) | ||
| RESOURCE_GROUP="kafka-eventhub-demo-rg" | ||
| NAMESPACE="kafka-eventhub-demo" # Must be globally unique! | ||
| LOCATION="eastus" # Change to your preferred region | ||
| ``` | ||
|
|
||
| **Step 3.1: Create a resource group** | ||
|
|
||
| ```bash | ||
| az group create \ | ||
| --name $RESOURCE_GROUP \ | ||
| --location $LOCATION | ||
| ``` | ||
|
|
||
| **Step 3.2: Create Event Hub namespace (Standard tier required for Kafka)** | ||
|
|
||
| ```bash | ||
| az eventhubs namespace create \ | ||
| --name $NAMESPACE \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --location $LOCATION \ | ||
| --sku Standard | ||
| ``` | ||
|
|
||
| **Step 3.3: Create the 'requests' topic (Event Hub)** | ||
|
|
||
| ```bash | ||
| az eventhubs eventhub create \ | ||
| --name requests \ | ||
| --namespace-name $NAMESPACE \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --partition-count 1 | ||
| ``` | ||
|
|
||
| **Step 3.4: Create the 'responses' topic (Event Hub)** | ||
|
|
||
| ```bash | ||
| az eventhubs eventhub create \ | ||
| --name responses \ | ||
| --namespace-name $NAMESPACE \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --partition-count 1 | ||
| ``` | ||
|
|
||
| Expected output after each command: | ||
|
|
||
| ```json | ||
| { | ||
| "id": "/subscriptions/.../resourceGroups/kafka-eventhub-demo-rg/...", | ||
| "name": "requests", | ||
| "status": "Active", | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| ### Step 4: Get Connection String | ||
|
|
||
| Retrieve the connection string needed for your WSO2 Integrator: BI services: | ||
|
|
||
| ```bash | ||
| # Get the primary connection string | ||
| az eventhubs namespace authorization-rule keys list \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --namespace-name $NAMESPACE \ | ||
| --name RootManageSharedAccessKey \ | ||
| --query primaryConnectionString \ | ||
| --output tsv | ||
| ``` | ||
|
|
||
| This outputs the connection string: | ||
|
|
||
| ``` | ||
| Endpoint=sb://kafka-eventhub-demo.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=abc123… | ||
| ``` | ||
|
|
||
| !!! important | ||
| Save this connection string (starting from `Endpoint`, not `sb://`). You'll need it for the Ballerina configuration. | ||
|
|
||
| ### Step 5: Verify Your Setup | ||
|
|
||
| Confirm that your Event Hub namespace and topics were created: | ||
|
|
||
| ```bash | ||
| # List Event Hubs (topics) in your namespace | ||
| az eventhubs eventhub list \ | ||
| --resource-group $RESOURCE_GROUP \ | ||
| --namespace-name $NAMESPACE \ | ||
| --output table | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ``` | ||
| Name Status PartitionCount | ||
| --------- -------- ---------------- | ||
| requests Active 1 | ||
| responses Active 1 | ||
| ``` | ||
|
|
||
| ### Step 6: Note Your Configuration Values | ||
|
|
||
| Based on the resources you created, your configuration values are: | ||
|
|
||
| | Setting | Value | | ||
| |---------|-------| | ||
| | Bootstrap Server | `<namespace>.servicebus.windows.net:9093` | | ||
| | Security Protocol | `SASL_SSL` | | ||
| | SASL Mechanism | `PLAIN` | | ||
| | Username | `$ConnectionString` (literal string) | | ||
| | Password | Your full connection string from Step 4 | | ||
|
|
||
| For example, if your namespace is `kafka-eventhub-demo`: | ||
|
|
||
| - Bootstrap Server: `kafka-eventhub-demo.servicebus.windows.net:9093` | ||
|
|
||
| ### Alternative: Using Azure Portal (GUI) | ||
|
|
||
| If you prefer a graphical interface, you can create the same resources through the Azure Portal: | ||
|
|
||
| 1. Go to [Azure Portal](https://portal.azure.com) | ||
| 2. Click **Create a resource** → Search for **Event Hubs** → Click **Create** | ||
| 3. Fill in: | ||
| - Resource group: Create new → `kafka-eventhub-demo-rg` | ||
| - Namespace name: `kafka-eventhub-demo` (must be unique) | ||
| - Pricing tier: **Standard** (Basic doesn't support Kafka) | ||
| 4. Click **Review + create** → **Create** | ||
| 5. After deployment, go to the namespace → **Event Hubs** → Create `requests` and `responses` | ||
| 6. Go to **Shared access policies** → **RootManageSharedAccessKey** → Copy connection string | ||
|
|
||
| ## Building the Reply Service | ||
|
|
||
| The Reply Service listens for incoming requests and sends back responses. We build this first so it's ready when the Request Service starts. | ||
|
|
||
| ### Step 1: Create a new integration project | ||
|
|
||
| 1. Open VS Code with WSO2 Integrator: BI installed. | ||
| 2. Click on the **BI** icon on the sidebar. | ||
| 3. Click on the **Create New Integration** button. | ||
| 4. Enter the project name as `ReplyService`. | ||
| 5. Select project directory and click on the **Create Integration** button. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/1-create-reply-service-project.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/1-create-reply-service-project.gif" alt="Create Reply Service Project" width="70%"></a> | ||
|
|
||
| ### Step 2: Create the Kafka Producer connection | ||
|
|
||
| The producer sends response messages back to the Request Service. | ||
|
|
||
| !!! important | ||
| Azure Event Hub requires a specific JAAS configuration format. We'll use `additionalProperties` to pass the SASL configuration directly. | ||
|
|
||
| 1. Click **+** next to **Connections** in the left panel. | ||
| 2. Select **Kafka Producer** under the Messaging category. | ||
| 3. Configure the connection: | ||
|
|
||
| | Setting | Value | | ||
| |---------|-------| | ||
| | Name | `responseProducer` | | ||
| | Bootstrap Servers | `<namespace>.servicebus.windows.net:9093` | | ||
| | Security Protocol | `kafka:PROTOCOL_SASL_SSL` | | ||
|
|
||
| 4. For `additionalProperties`, add these key-value pairs: | ||
|
|
||
| | Key | Value | | ||
| |-----|-------| | ||
| | `sasl.mechanism` | `PLAIN` | | ||
| | `sasl.jaas.config` | (see JAAS config format below) | | ||
|
|
||
| **JAAS Config Format:** | ||
|
|
||
| ``` | ||
| org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password="<your-connection-string>"; | ||
| ``` | ||
|
|
||
| 5. Click **Save**. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/2-create-kafka-producer-connection.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/2-create-kafka-producer-connection.png" alt="Create Kafka Producer Connection" width="70%"></a> | ||
|
|
||
| ### Step 3: Create the Kafka Event Handler | ||
|
|
||
| 1. Click **+** next to **Entry Points**. | ||
| 2. Select **Kafka Event Integration**. | ||
| 3. Configure: | ||
|
|
||
| | Setting | Value | | ||
| |---------|-------| | ||
| | Bootstrap Servers | `<namespace>.servicebus.windows.net:9093` | | ||
| | Topic | `requests` | | ||
|
|
||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-create-kafka-event-handler.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-create-kafka-event-handler.gif" alt="Create Kafka Event Handler" width="70%"></a> | ||
|
|
||
| 4. Click **Save**, then **Configure** to add consumer settings: | ||
|
|
||
| | Setting | Value | | ||
| |---------|-------| | ||
| | groupId | `reply-service-group` | | ||
| | offsetReset | `kafka:OFFSET_RESET_LATEST` | | ||
| | securityProtocol | `kafka:PROTOCOL_SASL_SSL` | | ||
| | requestTimeout | `60` | | ||
| | sessionTimeout | `30` | | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-2-create-kafka-event-handler.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-2-create-kafka-event-handler.png" alt="Create Kafka Event Handler" width="70%"></a> | ||
|
|
||
| 5. For `additionalProperties`, add the same SASL configuration: | ||
|
|
||
| | Key | Value | | ||
| |-----|-------| | ||
| | `sasl.mechanism` | `PLAIN` | | ||
| | `sasl.jaas.config` | (same JAAS config as producer) | | ||
|
|
||
| 6. Click **+ Add Handler** and select `onConsumerRecord` with `kafka:BytesConsumerRecord`. | ||
| 7. Click **Save** to open the flow diagram. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-3-create-kafka-event-handler.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/3-3-create-kafka-event-handler.png" alt="Create Kafka Event Handler" width="70%"></a> | ||
|
|
||
| ### Step 4: Implement the Reply Logic | ||
|
|
||
| In the `onConsumerRecord` flow: | ||
|
|
||
| 1. **Add a ForEach Block** | ||
| - Click **+** → Select **ForEach** under Control. | ||
| - Collection: `messages` (from inputs). | ||
| - Variable Name: `message`. | ||
| - Variable Type: `kafka:BytesConsumerRecord`. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/4-add-foreach-block.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/4-add-foreach-block.gif" alt="Add ForEach Block" width="70%"></a> | ||
|
|
||
| 2. **Deserialize the Request Message** | ||
| - Click **+** → Select function `fromBytes`. | ||
| - Name: `requestContent`. | ||
| - Type: `string`. | ||
| - Expression: `message.value.value`. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/5-deserialize-request-message.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/5-deserialize-request-message.gif" alt="Deserialize Request Message" width="70%"></a> | ||
|
|
||
| 3. **Log the Request** | ||
| - Click **+** → Search for `log` → Select `printInfo`. | ||
| - Message: `string `[Reply Service] Received request: ${requestContent}``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/6-log-request.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/6-log-request.gif" alt="Log the Request" width="70%"></a> | ||
|
|
||
| 4. **Create the Response** | ||
| - Click **+** → Select **Declare variable**. | ||
| - Name: `responseContent`. | ||
| - Type: `string`. | ||
| - Expression: `string `Response to: "${requestContent}" | Status: OK``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/7-create-response-variable.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/7-create-response-variable.gif" alt="Create Response Variable" width="70%"></a> | ||
|
|
||
| 5. **Send the Response** | ||
| - Click **+** → Select `responseProducer` → Choose `send`. | ||
| - Create a new `BytesProducerRecord` value: | ||
| ```ballerina | ||
| { topic: "responses", value: responseContent.toBytes() } | ||
| ``` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/8-send-response.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/8-send-response.gif" alt="Send Response" width="70%"></a> | ||
|
|
||
| 6. **Log the Response** | ||
| - Click **+** → Select `printInfo`. | ||
| - Message: `string `[Reply Service] Sent response: ${responseContent}``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/9-log-response.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/9-log-response.gif" alt="Log Response" width="70%"></a> | ||
|
|
||
| ## Building the Request Service | ||
|
|
||
| The Request Service exposes an HTTP endpoint to trigger requests and listens for responses. | ||
|
|
||
| ### Step 1: Create a new integration project | ||
|
|
||
| Create a new integration named `RequestService` following the same steps as for the Reply Service. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/10-create-request-service-project.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/10-create-request-service-project.gif" alt="Create Request Service Project" width="70%"></a> | ||
|
|
||
| ### Step 2: Create the Kafka Producer connection | ||
|
|
||
| 1. Add a Kafka Producer connection named `requestProducer`. | ||
| 2. Configure with the same settings as Reply Service: | ||
| - Bootstrap Servers: `<namespace>.servicebus.windows.net:9093` | ||
| - Security Protocol: `kafka:PROTOCOL_SASL_SSL` | ||
| - `additionalProperties` with `sasl.mechanism` and `sasl.jaas.config` | ||
|
|
||
| ### Step 3: Create the HTTP Service | ||
|
|
||
| 1. Click **+** next to **Entry Points**. | ||
| 2. Select **HTTP Service**. | ||
| 3. Configure: | ||
| - Path: `/api` | ||
| - Port: `8080` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-create-http-service.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-create-http-service.gif" alt="Create HTTP Service" width="70%"></a> | ||
|
|
||
| 4. Add a resource: | ||
| - Method: `POST` | ||
| - Path: `/request` | ||
| - Payload: `string` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-2-create-http-service.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/11-2-create-http-service.gif" alt="Create HTTP Service" width="70%"></a> | ||
|
|
||
| ### Step 4: Implement the Request Logic | ||
|
|
||
| In the HTTP `POST /request` resource flow: | ||
|
|
||
| 1. **Log the Request** | ||
| - Add `printInfo`: `string `[Request Service] Sending request: ${payload}``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/12-log-request.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/12-log-request.png" alt="Log Request" width="70%"></a> | ||
|
|
||
| 2. **Send to Kafka** | ||
| - Call `requestProducer->send`: | ||
| ```ballerina | ||
| { topic: "requests", value: payload.toBytes() } | ||
| ``` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/13-send-to-kafka.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/13-send-to-kafka.gif" alt="Send to Kafka" width="70%"></a> | ||
|
|
||
| 3. **Return Response** | ||
| ```ballerina | ||
| string `Request sent successfully: ${payload}` | ||
| ``` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/14-return-response.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/14-return-response.gif" alt="Return Response" width="70%"></a> | ||
|
|
||
| ### Step 5: Create the Response Listener | ||
|
|
||
| 1. Add a **Kafka Event Integration** entry point. | ||
| 2. Configure: | ||
| - Topic: `responses` | ||
| - Group ID: `request-service-group` | ||
| - Security Protocol: `kafka:PROTOCOL_SASL_SSL` | ||
| - `additionalProperties` with `sasl.mechanism` and `sasl.jaas.config` | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-create-response-listener.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-create-response-listener.gif" alt="Create Response Listener" width="70%"></a> | ||
|
|
||
| 3. Click **+ Add Handler** and select `onConsumerRecord` with `kafka:BytesConsumerRecord`. | ||
| 4. Click **Save** to open the flow diagram. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-2-create-response-listener.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-2-create-response-listener.gif" alt="Create Response Listener" width="70%"></a> | ||
|
|
||
| In the `onConsumerRecord` flow: | ||
|
|
||
| 1. **Add a ForEach Block** | ||
| - Click **+** → Select **ForEach** under Control. | ||
| - Collection: `messages` (from inputs). | ||
| - Variable Name: `message`. | ||
| - Variable Type: `kafka:BytesConsumerRecord`. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-3-create-response-listener.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-3-create-response-listener.gif" alt="Create Response Listener" width="70%"></a> | ||
|
|
||
| 2. **Deserialize the Response Message** | ||
| - Click **+** → Select function `fromBytes`. | ||
| - Name: `responseContent`. | ||
| - Type: `string`. | ||
| - Expression: `message.value.value`. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-4-create-response-listener.gif"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/15-4-create-response-listener.gif" alt="Create Response Listener" width="70%"></a> | ||
|
|
||
| 3. **Log the Response** | ||
| - Message: `string `[Request Service] Received response: ${responseContent}``. | ||
|
|
||
| <a href="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/16-log-received-response.png"><img src="{{base_path}}/assets/img/integration-guides/event-integration/kafka/kafka-request-reply-pattern-with-azure-event-hub/16-log-received-response.png" alt="Log Received Response" width="70%"></a> | ||
|
|
||
| ## Running the Services | ||
|
|
||
| ### Step 1: Start the Reply Service | ||
|
|
||
| ```bash | ||
| cd ReplyService | ||
| bal run | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ``` | ||
| Compiling source | ||
| wso2/reply_service:0.1.0 | ||
|
|
||
| Running executable | ||
| ``` | ||
|
|
||
| ### Step 2: Start the Request Service | ||
|
|
||
| In a new terminal: | ||
|
|
||
| ```bash | ||
| cd RequestService | ||
| bal run | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ``` | ||
| Compiling source | ||
| wso2/request_service:0.1.0 | ||
|
|
||
| Running executable | ||
| ``` | ||
|
|
||
| ### Step 3: Send a Test Request | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:8080/api/request \ | ||
| -H "Content-Type: text/plain" \ | ||
| -d "Hello Azure Event Hub" | ||
| ``` | ||
|
|
||
| Response: | ||
|
|
||
| ``` | ||
| Request sent: Hello Azure Event Hub | ||
| ``` | ||
|
|
||
| ### Step 4: Verify the Logs | ||
|
|
||
| **Request Service logs:** | ||
|
|
||
| ``` | ||
| [Request Service] Sending request: Hello Azure Event Hub | ||
| [Request Service] Received response: Response to: "Hello Azure Event Hub" | Status: OK | ||
| ``` | ||
|
|
||
| **Reply Service logs:** | ||
|
|
||
| ``` | ||
| [Reply Service] Received request: Hello Azure Event Hub | ||
| [Reply Service] Sent response: Response to: "Hello Azure Event Hub" | Status: OK | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Connection Timeout / Topic Not Found in Metadata | ||
|
|
||
| - Use `additionalProperties`: Azure Event Hub requires SASL configuration via `additionalProperties` with `sasl.mechanism` and `sasl.jaas.config` | ||
| - Verify your namespace name is correct | ||
| - Ensure port 9093 is not blocked by firewall | ||
| - Check the connection string is complete | ||
|
|
||
| ### Authentication Failed | ||
|
|
||
| - Verify the JAAS config format is exactly: | ||
| ``` | ||
| org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password="<connection-string>"; | ||
| ``` | ||
| - The `$ConnectionString` must be a literal string (not a variable) | ||
| - The password must be your complete connection string starting with `Endpoint=sb://...` | ||
|
|
||
| ### No Messages Received | ||
|
|
||
| - Ensure both topics exist in Azure | ||
| - Check consumer group IDs are different for each service | ||
| - Verify `offsetReset` is set to `LATEST` for new consumers | ||
|
|
||
| ## Summary | ||
|
|
||
| You have successfully built a request-reply messaging system using: | ||
|
|
||
| - Azure Event Hub as a Kafka-compatible message broker | ||
| - Two topics (`requests` and `responses`) for bidirectional communication | ||
| - SASL_SSL authentication with Azure connection strings | ||
| - Event-driven Kafka listeners for consuming messages | ||
| - HTTP endpoint for triggering requests | ||
|
|
||
| This pattern is useful for: | ||
|
|
||
| - Asynchronous request-response workflows | ||
| - Decoupling services while maintaining communication | ||
| - Building scalable microservices architectures | ||
|
|
||
| ## Cleanup: Delete Azure Resources | ||
|
|
||
| When you're done with this tutorial, delete the Azure resources to avoid ongoing charges. | ||
|
|
||
| ### Option 1: Delete Using Azure CLI (Recommended) | ||
|
|
||
| This single command deletes the resource group and everything in it: | ||
|
|
||
| ```bash | ||
| # Delete the resource group (includes namespace and all Event Hubs) | ||
| az group delete \ | ||
| --name kafka-eventhub-demo-rg \ | ||
| --yes \ | ||
| --no-wait | ||
| ``` | ||
|
|
||
| The `--no-wait` flag returns immediately while deletion continues in the background. | ||
|
|
||
| To verify deletion: | ||
|
|
||
| ```bash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Add language specifications to all fenced code blocks for syntax highlighting.
Numerous code blocks lack language identifiers (e.g., ```bash, ```json), disabling syntax highlighting and impacting readability. This was flagged in previous reviews and remains unaddressed.
🔎 Proposed fixes for code block language identifiers
After installation, verify Azure CLI is working:
-```
+```bash
az --versionOpen a terminal and authenticate with your Azure account:
- +bash
az login
This opens a browser window for authentication. After signing in, you'll see your subscription details in the terminal:
-```
+```json
[
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
@@ ... (abbreviated for space)
If you have multiple subscriptions, set the one you want to use:
-```
+```bash
# List all subscriptions
az account list --output table
Run these commands to create all required Azure resources:
-```
+```bash
# Set configuration variables
# IMPORTANT: Change NAMESPACE to something unique (e.g., add your initials)
RESOURCE_GROUP="kafka-eventhub-demo-rg"
NAMESPACE="kafka-eventhub-demo" # Must be globally unique!
LOCATION="eastus" # Change to your preferred region
This outputs the connection string:
- +plaintext
Endpoint=sb://kafka-eventhub-demo.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=abc123…
Expected output:
-```
+```plaintext
Name Status PartitionCount
--------- -------- ----------------
requests Active 1
responses Active 1
**JAAS Config Format:**
-
org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password="<your-connection-string>";- Click + → Select function
fromBytes. - Name:
requestContent. - Type:
string. - Expression:
message.value.value.
- Click + → Select function
+```ballerina
{ topic: "responses", value: responseContent.toBytes() }
- Click **+** → Select `responseProducer` → Choose `send`.
- Create a new `BytesProducerRecord` value:
- ```ballerina
+ ```ballerina
{ topic: "requests", value: payload.toBytes() }
```
- ```ballerina
+```ballerina
string `Request sent successfully: ${payload}`
- +bash
cd ReplyService
bal run
Expected output:
-```
+```plaintext
Compiling source
wso2/reply_service:0.1.0
Running executable
- +bash
cd RequestService
bal run
Expected output:
-```
+```plaintext
Compiling source
wso2/request_service:0.1.0
Running executable
- +bash
curl -X POST http://localhost:8080/api/request
-H "Content-Type: text/plain"
-d "Hello Azure Event Hub"
Response:
-```
+```plaintext
Request sent: Hello Azure Event Hub
Request Service logs:
- +plaintext
[Request Service] Sending request: Hello Azure Event Hub
[Request Service] Received response: Response to: "Hello Azure Event Hub" | Status: OK
**Reply Service logs:**
-```
+```plaintext
[Reply Service] Received request: Hello Azure Event Hub
[Reply Service] Sent response: Response to: "Hello Azure Event Hub" | Status: OK
- Verify the JAAS config format is exactly:
-
-
org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password="<connection-string>";
This single command deletes the resource group and everything in it:
- +bash
Delete the resource group (includes namespace and all Event Hubs)
az group delete
--name kafka-eventhub-demo-rg
--yes
--no-wait
To verify deletion:
-```
+```bash
# Check if resource group still exists
az group show --name kafka-eventhub-demo-rg
</details>
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
160-160: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
170-170: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
176-176: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
190-190: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
202-202: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
210-210: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
---
212-212: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
218-218: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
---
220-220: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
228-228: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
---
230-230: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
238-238: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
---
240-240: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
250-250: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
263-263: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
275-275: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
275-275: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
286-286: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
296-296: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
296-296: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
373-373: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
373-373: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
441-441: Spaces inside code span elements
(MD038, no-space-in-code)
---
449-449: Spaces inside code span elements
(MD038, no-space-in-code)
---
456-456: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
464-464: Spaces inside code span elements
(MD038, no-space-in-code)
---
499-499: Inconsistent indentation for list items at the same level
Expected: 5; Actual: 4
(MD005, list-indent)
---
508-508: Spaces inside code span elements
(MD038, no-space-in-code)
---
514-514: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
521-521: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
562-562: Spaces inside code span elements
(MD038, no-space-in-code)
---
570-570: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
577-577: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
577-577: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
588-588: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
595-595: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
595-595: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
604-604: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
612-612: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
612-612: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
620-620: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
620-620: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
627-627: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
627-627: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
644-644: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
---
644-644: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
680-680: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
---
692-692: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
</details>
</details>
<!-- fingerprinting:phantom:triton:mongoose -->
<!-- This is an auto-generated comment by CodeRabbit -->
Purpose
$title
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.