feat: add aggregator service with Kafka consumer skeleton#2263
Conversation
New component that consumes patchman.advisory.update topic. Includes deployment configs, health probes, and a stub handler for advisory update events. Notifications are disabled until the evaluator handoff.
Reviewer's GuideIntroduces a new aggregator service wired into the existing app, with deployment/docker-compose/Dockerfile wiring, Kafka consumer skeleton, health/metrics server, and optional notifications publisher, but no business logic yet. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2263 +/- ##
==========================================
- Coverage 59.03% 58.75% -0.29%
==========================================
Files 144 147 +3
Lines 9194 9233 +39
==========================================
- Hits 5428 5425 -3
- Misses 3194 3236 +42
Partials 572 572
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The
enableNotificationsflag is read fromPodConfigbut never used to gate notification behavior, so either remove it for now or wire it intoconfigureNotifications/ publishing logic to avoid confusion about how notifications are toggled. - Consider validating
consumer_countfromPodConfig(e.g., enforcing a minimum of 1) so a misconfiguration doesn’t silently result in zero Kafka consumers being spawned.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `enableNotifications` flag is read from `PodConfig` but never used to gate notification behavior, so either remove it for now or wire it into `configureNotifications` / publishing logic to avoid confusion about how notifications are toggled.
- Consider validating `consumer_count` from `PodConfig` (e.g., enforcing a minimum of 1) so a misconfiguration doesn’t silently result in zero Kafka consumers being spawned.
## Individual Comments
### Comment 1
<location path="aggregator/aggregator.go" line_range="19-21" />
<code_context>
+ consumerCount int
+)
+
+func readPodConfig() {
+ consumerCount = utils.PodConfig.GetInt("consumer_count", 1)
+ enableNotifications = utils.PodConfig.GetBool("instant_notifications", false)
+}
+
</code_context>
<issue_to_address>
**suggestion:** Consider validating `consumer_count` to avoid silently running with zero consumers
If `consumer_count` is set to 0 or negative, no readers will be spawned and the service will appear healthy while not consuming messages. Consider enforcing a minimum of 1 (e.g., clamp `<= 0` to 1 and log a warning) to guard against misconfiguration.
Suggested implementation:
```golang
import (
"app/base"
"app/base/core"
"app/base/mqueue"
"app/base/utils"
"log"
"sync"
"github.com/gin-gonic/gin"
)
```
```golang
func readPodConfig() {
consumerCount = utils.PodConfig.GetInt("consumer_count", 1)
if consumerCount <= 0 {
log.Printf("invalid consumer_count=%d, defaulting to 1", consumerCount)
consumerCount = 1
}
enableNotifications = utils.PodConfig.GetBool("instant_notifications", false)
}
```
</issue_to_address>
### Comment 2
<location path="aggregator/notifications.go" line_range="10-12" />
<code_context>
+
+var notificationsPublisher mqueue.Writer
+
+func configureNotifications() {
+ if topic := utils.CoreCfg.NotificationsTopic; topic != "" {
+ notificationsPublisher = mqueue.NewKafkaWriterFromEnv(topic)
+ }
+}
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Align `instant_notifications` config with notifications writer initialization
`configureNotifications` still creates a writer whenever `NotificationsTopic` is set, ignoring `instant_notifications`. If that flag is intended to control whether notifications are produced, also check `enableNotifications` before initializing the writer; otherwise, remove the unused flag to avoid misleading config.
Suggested implementation:
```golang
func configureNotifications() {
// Only initialize the notifications writer if notifications are enabled
if !enableNotifications {
return
}
if topic := utils.CoreCfg.NotificationsTopic; topic != "" {
notificationsPublisher = mqueue.NewKafkaWriterFromEnv(topic)
}
}
```
To fully align `instant_notifications` with writer initialization, ensure:
1. `enableNotifications` is derived from the `instant_notifications` config (or equivalent) in your configuration bootstrap code, e.g.:
- `enableNotifications = utils.CoreCfg.InstantNotifications` (or similar).
2. Any code path that toggles `instant_notifications` updates `enableNotifications` before `configureNotifications()` is called.
3. If `enableNotifications` is not yet defined in this package, declare it (likely as a `bool` at package scope) and initialize it alongside other feature flags, respecting existing conventions in the aggregator package.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| func readPodConfig() { | ||
| consumerCount = utils.PodConfig.GetInt("consumer_count", 1) | ||
| enableNotifications = utils.PodConfig.GetBool("instant_notifications", false) |
There was a problem hiding this comment.
suggestion: Consider validating consumer_count to avoid silently running with zero consumers
If consumer_count is set to 0 or negative, no readers will be spawned and the service will appear healthy while not consuming messages. Consider enforcing a minimum of 1 (e.g., clamp <= 0 to 1 and log a warning) to guard against misconfiguration.
Suggested implementation:
import (
"app/base"
"app/base/core"
"app/base/mqueue"
"app/base/utils"
"log"
"sync"
"github.com/gin-gonic/gin"
)func readPodConfig() {
consumerCount = utils.PodConfig.GetInt("consumer_count", 1)
if consumerCount <= 0 {
log.Printf("invalid consumer_count=%d, defaulting to 1", consumerCount)
consumerCount = 1
}
enableNotifications = utils.PodConfig.GetBool("instant_notifications", false)
}| func configureNotifications() { | ||
| if topic := utils.CoreCfg.NotificationsTopic; topic != "" { | ||
| notificationsPublisher = mqueue.NewKafkaWriterFromEnv(topic) |
There was a problem hiding this comment.
suggestion (bug_risk): Align instant_notifications config with notifications writer initialization
configureNotifications still creates a writer whenever NotificationsTopic is set, ignoring instant_notifications. If that flag is intended to control whether notifications are produced, also check enableNotifications before initializing the writer; otherwise, remove the unused flag to avoid misleading config.
Suggested implementation:
func configureNotifications() {
// Only initialize the notifications writer if notifications are enabled
if !enableNotifications {
return
}
if topic := utils.CoreCfg.NotificationsTopic; topic != "" {
notificationsPublisher = mqueue.NewKafkaWriterFromEnv(topic)
}
}To fully align instant_notifications with writer initialization, ensure:
enableNotificationsis derived from theinstant_notificationsconfig (or equivalent) in your configuration bootstrap code, e.g.:enableNotifications = utils.CoreCfg.InstantNotifications(or similar).
- Any code path that toggles
instant_notificationsupdatesenableNotificationsbeforeconfigureNotifications()is called. - If
enableNotificationsis not yet defined in this package, declare it (likely as aboolat package scope) and initialize it alongside other feature flags, respecting existing conventions in the aggregator package.
Summary
patchman.advisory.updatetopicWhat's next
This is the foundation for the aggregator consumer, which will add message deserialization, batching by (rh_account_id, workspace_id), account_advisory table updates, and parity checks
Follow-up
Test plan
Secure Coding Practices Checklist GitHub Link
Secure Coding Checklist
Summary by Sourcery
Introduce a new aggregator service that consumes advisory update Kafka messages and prepares for future advisory aggregation and notifications.
New Features:
Enhancements:
Build:
Documentation:
Summary by Sourcery
Introduce a new aggregator service that consumes advisory update Kafka messages and is wired into the existing application and deployment stack.
New Features:
Enhancements:
Build:
Documentation: