Skip to content

Kafka async and logging - #2378

Open
pindo696 wants to merge 4 commits into
RedHatInsights:masterfrom
pindo696:kafka-async-and-logging
Open

Kafka async and logging#2378
pindo696 wants to merge 4 commits into
RedHatInsights:masterfrom
pindo696:kafka-async-and-logging

Conversation

@pindo696

@pindo696 pindo696 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Refactoring sending kafka async messages and improved logging,
Updated tests,
RHINENG-24284.
(Hope something has not been lost during the push)

Secure Coding Practices Checklist GitHub Link

Secure Coding Checklist

  • Input Validation
  • Output Encoding
  • Authentication and Password Management
  • Session Management
  • Access Control
  • Cryptographic Practices
  • Error Handling and Logging
  • Data Protection
  • Communication Security
  • System Configuration
  • Database Security
  • File Management
  • Memory Management
  • General Coding Practices

Summary by Sourcery

Convert Kafka message sending across the service to fully async usage with improved error logging and semaphore handling for batch operations.

Bug Fixes:

  • Ensure Kafka send failures are logged with context and re-raised where appropriate instead of failing silently.
  • Guarantee semaphore release around re-evaluation batch sends to avoid deadlocks when Kafka operations fail.

Enhancements:

  • Refactor Kafka producer helper methods and call sites to use awaitable send APIs instead of creating background futures and passing explicit event loops.
  • Improve logging messages for Kafka send operations and payload tracking to provide clearer operational visibility.
  • Simplify re-evaluation batching logic by centralizing batch send-and-release behavior in shared helper coroutines.

Tests:

  • Adjust notificator queue tests to work with async notification sending by mocking async helpers instead of sync functions.

@sourcery-ai

sourcery-ai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors Kafka messaging to be fully async end-to-end, tightening logging and error handling, and adjusts recalc batching and notification flows to await Kafka sends explicitly while preserving existing control-flow semantics.

Sequence diagram for async evaluation and Kafka messaging

sequenceDiagram
    participant InventoryProcessor
    participant GrouperQueue
    participant EvaluatorProcessor
    participant KafkaPayloadTracker
    participant KafkaRemediations
    participant KafkaNotifications
    participant KafkaInventoryViews

    InventoryProcessor->>InventoryProcessor: _process_upload(msg)
    InventoryProcessor->>InventoryProcessor: _send_for_evaluation(org_id, inventory_id, request_id, reporter, timestamp, import_status)
    InventoryProcessor->>GrouperQueue: grouper.send(msg, key=org_id)
    G rouperQueue-->>InventoryProcessor: await complete

    GrouperQueue->>GrouperQueue: _send_for_evaluation(item, org_id, inventory_id, msg)
    GrouperQueue->>KafkaPayloadTracker: send_msg_to_payload_tracker(payload_tracker, msg, status="processing")
    KafkaPayloadTracker-->>GrouperQueue: await complete
    GrouperQueue->>EvaluatorProcessor: evaluator.send(msg)
    EvaluatorProcessor-->>GrouperQueue: await complete

    EvaluatorProcessor->>EvaluatorProcessor: _evaluate_system(...)
    EvaluatorProcessor->>KafkaRemediations: send_remediations_update(remediations_results, inventory_id, fixable_sys_vuln_rows)
    KafkaRemediations-->>EvaluatorProcessor: await complete
    EvaluatorProcessor->>KafkaNotifications: send_notifications(evaluator_results, new_system_vulns, [], [], rh_account_id, org_id)
    KafkaNotifications-->>EvaluatorProcessor: await complete
    EvaluatorProcessor->>KafkaInventoryViews: send_inventory_views(inventory_views_results, request_id, inventory_id, ...)
    KafkaInventoryViews-->>EvaluatorProcessor: await complete

    EvaluatorProcessor->>KafkaPayloadTracker: send_msg_to_payload_tracker(payload_tracker, msg, status="success" | "error")
    KafkaPayloadTracker-->>EvaluatorProcessor: await complete
Loading

Sequence diagram for async recalc batch send with semaphore

sequenceDiagram
    participant RecalcCaller as RecalcAccounts_or_VmaasSync
    participant BATCH_SEMAPHORE
    participant Helper as _send_recalc_batch_and_release
    participant EvaluatorQueue as EVALUATOR_QUEUE

    loop while rows
        RecalcCaller->>BATCH_SEMAPHORE: acquire()
        BATCH_SEMAPHORE-->>RecalcCaller: acquired
        RecalcCaller->>RecalcCaller: _create_kafka_msg(rows)
        RecalcCaller->>Helper: _send_recalc_batch_and_release(msgs)
        activate Helper
        Helper->>EvaluatorQueue: send_list(msgs)
        EvaluatorQueue-->>Helper: await complete
        Helper->>BATCH_SEMAPHORE: release()
        deactivate Helper
    end

    RecalcCaller->>RecalcCaller: asyncio.gather(*send_tasks) (vmaas_sync) / run_until_complete(...) (admin_handler)
Loading

File-Level Changes

Change Details Files
Make Kafka producer interface and all call sites fully async and remove explicit event loop plumbing.
  • Change Partitioners.org_id_partitioner key type from str to bytes to match Kafka client expectations.
  • Convert KafkaProducer.send/send_list/send_bytes to async methods that await send_one/send_many/send_raw instead of scheduling ensure_future with an explicit loop parameter.
  • Update utility functions (payload tracker, remediations update, notifications, inventory views) to be async, awaiting producer.send and removing the loop parameter.
  • Adjust evaluator, advisor_processor, inventory_processor, grouper.queue, listener, and notificator flows to await the new async send APIs instead of calling them synchronously or passing a loop.
common/mqueue.py
common/utils.py
evaluator/processor.py
listener/advisor_processor.py
listener/inventory_processor.py
grouper/queue.py
listener/listener.py
notificator/notificator_queue.py
Improve Kafka send logging and error handling semantics.
  • Replace bare LOGGER.debug(res) with structured debug messages that include the Kafka topic and result in all producer send methods.
  • On KafkaError in send_one/send_many/send_raw, mark the producer as disconnected, log an exception with context (including topic and batch size where applicable), and re-raise so callers can react.
  • In send_msg_to_payload_tracker, log before sending, catch KafkaError, log an error, and intentionally swallow the exception so business logic continues unaffected.
common/mqueue.py
common/utils.py
Refine re-evaluation batching to await Kafka sends while correctly managing the batch semaphore.
  • Introduce helper coroutine _send_recalc_batch_and_release in admin_handler and vmaas_sync that awaits EVALUATOR_QUEUE.send_list and releases BATCH_SEMAPHORE in a finally block.
  • Refactor RecalcBase._create_kafka_msg_task into _create_kafka_msg that only builds the message list; callers now drive the async send and counting explicitly.
  • In RecalcAccounts and related handlers, replace task/add_done_callback/loop.run_until_complete(task) with building msgs, running loop.run_until_complete on _send_recalc_batch_and_release, and computing totals from len(msgs).
  • In vmaas_sync.re_evaluate_systems, accumulate coroutines in send_tasks (instead of futures with callbacks), then await them via asyncio.gather while logging the number of pending sends.
manager/admin_handler.py
vmaas_sync/vmaas_sync.py
Align notificator Kafka sending and tests with the async API.
  • Make NotificatorQueue._send_kafka_notif async and await notifications_topic.send instead of calling it synchronously.
  • Adjust _process_normal_queue to await _send_kafka_notif before incrementing metrics and updating state.
  • Update notificator_queue tests to mock _send_kafka_notif as an async function that records messages instead of a sync function.
notificator/notificator_queue.py
tests/notificator_tests/test_notificator_queue.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

SC Environment Impact Assessment

Overall Impact: 🟡 MEDIUM

View full report

Summary

  • Total Issues: 2
  • 🟡 Medium: 2

Detailed Findings

🟡 MEDIUM Impact

Kafka topic configuration change detected

  • File: common/mqueue.py
  • Category: kafka_topics
  • Details:
    • Found Kafka topic %s: %s", self.topic in common/mqueue.py at line 146
    • Found Kafka topic %s", self.topic in common/mqueue.py at line 149
    • Found Kafka topic %s: %s", self.topic in common/mqueue.py at line 159
    • Found Kafka topic %s (batch size %d)", self.topic in common/mqueue.py at line 162
    • Found Kafka topic %s: %s", self.topic in common/mqueue.py at line 170
  • Recommendation: New or modified Kafka topics may need to be created in SC Environment Kafka cluster.

Kafka topic configuration change detected

  • File: common/utils.py
  • Category: kafka_topics
  • Details:
    • Found Kafka producer.topic %s message failed", producer.topic in common/utils.py at line 131
  • Recommendation: New or modified Kafka topics may need to be created in SC Environment Kafka cluster.

Required Actions

  • Review all findings above
  • Verify SC Environment compatibility for all detected changes
  • Update deployment documentation if needed
  • Coordinate with ROSA Core team or deployment timeline

This assessment was automatically generated. Please review carefully and consult with the ROSA Core team for critical/high impact changes.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In RecalcAccounts.handle_put, total_scheduled is now overwritten with len(msgs) on each loop iteration instead of accumulated as before; this changes the semantics from a total count to just the last batch size and is likely a regression compared to the previous behavior.
  • In utils.send_msg_to_payload_tracker, the KafkaError is fully swallowed after logging; if payload-tracker failures should be observable upstream, consider surfacing a metric or returning an error flag so callers can react instead of always treating the flow as successful.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `RecalcAccounts.handle_put`, `total_scheduled` is now overwritten with `len(msgs)` on each loop iteration instead of accumulated as before; this changes the semantics from a total count to just the last batch size and is likely a regression compared to the previous behavior.
- In `utils.send_msg_to_payload_tracker`, the `KafkaError` is fully swallowed after logging; if payload-tracker failures should be observable upstream, consider surfacing a metric or returning an error flag so callers can react instead of always treating the flow as successful.

## Individual Comments

### Comment 1
<location path="vmaas_sync/vmaas_sync.py" line_range="389-393" />
<code_context>
-                future = EVALUATOR_QUEUE.send_list(msgs, loop=loop)
-                future.add_done_callback(lambda x: BATCH_SEMAPHORE.release())
-                futures.append(future)
+                send_tasks.append(_send_recalc_batch_and_release(msgs))

-            if futures:
-                LOGGER.info("Waiting for %s Kafka send operations to complete", len(futures))
-                loop.run_until_complete(asyncio.gather(*futures))
+            if send_tasks:
+                LOGGER.info("Waiting for %s Kafka send operations to complete", len(send_tasks))
+                loop.run_until_complete(asyncio.gather(*send_tasks))

             LOGGER.info("%s systems scheduled for re-evaluation", total_scheduled)
</code_context>
<issue_to_address>
**issue (bug_risk):** Potential deadlock: semaphore is acquired in the loop but only released inside tasks that are scheduled after the loop terminates.

Because each iteration only appends the coroutine to `send_tasks` and doesn’t schedule it, no `_send_recalc_batch_and_release` call runs until after the loop finishes and `asyncio.gather(*send_tasks)` is invoked. Once the semaphore permits are exhausted, `loop.run_until_complete(BATCH_SEMAPHORE.acquire())` will block indefinitely, since no running task can release the semaphore. Consider either scheduling the send immediately (e.g. `send_tasks.append(loop.create_task(_send_recalc_batch_and_release(msgs)))`) or restoring the per-iteration send pattern so releases can occur while the loop is still acquiring.
</issue_to_address>

### Comment 2
<location path="notificator/notificator_queue.py" line_range="110-113" />
<code_context>
             }
         ]

-    def _send_kafka_notif(
+    async def _send_kafka_notif(
         self,
</code_context>
<issue_to_address>
**suggestion:** The `loop` parameter to `_send_kafka_notif` is now unused and can be removed.

Since `_send_kafka_notif` is now async and uses `await self.notifications_topic.send(msg)`, the `loop` parameter is unused. Please remove it from the signature and update callers to avoid confusion about which event loop is in play.

Suggested implementation:

```python
    async def _send_kafka_notif(
        self,
        org_id: str,
        inventory_id: str,
            msg["org_id"] = org_id

```

```python

```

1. Remove the `loop` argument at all call sites of `_send_kafka_notif` in this file and elsewhere in the codebase. For example, change calls like:
   - `await self._send_kafka_notif(loop, org_id, inventory_id, msg)` to `await self._send_kafka_notif(org_id, inventory_id, msg)`.
2. If the `_send_kafka_notif` signature uses a typed or defaulted `loop` parameter (e.g. `loop: AbstractEventLoop` or `loop: Optional[AbstractEventLoop] = None`), delete that entire parameter definition from the function signature to keep it consistent with the updated callers.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread vmaas_sync/vmaas_sync.py Outdated
Comment thread notificator/notificator_queue.py
@pindo696

Copy link
Copy Markdown
Contributor Author

/retest

@pindo696
pindo696 force-pushed the kafka-async-and-logging branch from 517046f to 36d09c9 Compare June 17, 2026 12:08
@jdobes

jdobes commented Jul 24, 2026

Copy link
Copy Markdown
Member

Needs rebase pls

pindo696 added 3 commits July 27, 2026 16:24
RE_EVALUATION_KAFKA_BATCHES limits number of tasks in flight, we need to schedule them for processing midrun inside while loop allowing multiple tasks in flight. RHINENG-24284
@pindo696
pindo696 force-pushed the kafka-async-and-logging branch from 36d09c9 to 636ee84 Compare July 27, 2026 14:32
Changes that were lost during merge conflicts resolution.
@pindo696
pindo696 force-pushed the kafka-async-and-logging branch from a276f5b to f75058b Compare July 28, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants