Skip to content

RHINENG-26348: add job to refill 0 partition - #2289

Open
TenSt wants to merge 2 commits into
RedHatInsights:masterfrom
TenSt:stepan/RHINENG-26348-add-job-to-refill-0-partition
Open

RHINENG-26348: add job to refill 0 partition#2289
TenSt wants to merge 2 commits into
RedHatInsights:masterfrom
TenSt:stepan/RHINENG-26348-add-job-to-refill-0-partition

Conversation

@TenSt

@TenSt TenSt commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

This PR:

  • adds one-shot system_advisories_0_recovery job to recalc non-stale bucket-0 systems
  • publishes to patchman.evaluator.recalc in 500/msg chunks with skip_notifications
  • gates via JOBS_CONFIG + disabled CJI (SA0_RECOVERY_DISABLED, default true)

Note: I've tested locally and all looks good. We will tests everything in stage before going to production even that stage doesn't have the corrupted partition.

Summary by Sourcery

Introduce a one-shot recovery job to recalc non-stale bucket-0 systems while marking advisories as notified without sending instant notifications, wired through evaluator events and deployment config.

New Features:

  • Add system_advisories_0_recovery job that selects non-stale bucket-0 systems and publishes recalc events to the evaluator topic with skip_notifications set.
  • Expose a SkipNotifications flag on platform events and propagate it through evaluation to support mark-notified-only advisory handling.

Enhancements:

  • Refactor advisory notification publishing to support a skipPublish mode while still updating advisory_account_data.notified.
  • Generalize evaluator event batching to accept a configurable batch size and reuse logic for both normal and skip-notifications flows.

Build:

  • Wire the system-advisories-0-recovery job into the application entrypoint and task configuration.
  • Update ClowdApp deployment to define the system-advisories-0-recovery job and a corresponding ClowdJobInvocation gated via JOBS_CONFIG and SA0_RECOVERY_DISABLED parameters.

Tests:

  • Add tests covering skip_notifications behavior end-to-end in evaluator notifications, including mark-notified-only flows with no Kafka messages.
  • Add tests for PlatformEvent skip_notifications JSON serialization and for skip-notifications event chunking into the evaluator topic.
  • Add tests validating the recovery job’s bucket-0 selection query and that recovery publishes events with SkipNotifications set.

@TenSt
TenSt requested a review from a team as a code owner July 30, 2026 16:59
@sourcery-ai

sourcery-ai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

Implements a one-shot recovery job that publishes recalc events for non-stale bucket-0 systems with advisory notifications skipped, adds skip-notification semantics end-to-end in evaluator and platform events, and wires the job into clowdapp configuration and tests.

File-Level Changes

Change Details Files
Add a one-shot system_advisories_0_recovery job that publishes recalc events with skip_notifications for non-stale bucket-0 systems.
  • Introduce tasks/system_advisories_0_recovery package with Configure, Run, publishBucket0Recalc, and getNonStaleBucket0InventoryIDs functions.
  • Query non-stale systems in system_advisories partition remainder 0 using satisfies_hash_partition and order by account and id.
  • Publish recovery recalc events via EvalDataSlice.WriteEventsSkipNotifications using a dedicated Kafka writer and 500-system batch size.
  • Add configuration flag EnableSystemAdvisories0Recovery sourced from JOBS_CONFIG and gate Run() on it.
  • Wire the new job into main.runJob and clowdapp.yaml as a one-shot job plus a dedicated ClowdJobInvocation gated by SA0_RECOVERY_DISABLED and JOBS_CONFIG.
tasks/system_advisories_0_recovery/recovery.go
tasks/system_advisories_0_recovery/recovery_test.go
tasks/config.go
main.go
deploy/clowdapp.yaml
Extend PlatformEvent and event-writing pipeline to support skip_notifications and chunked recovery publishing.
  • Add SkipNotifications field to PlatformEvent JSON (skip_notifications, omitempty) with semantics documented for recovery recalc.
  • Refactor batching helpers to accept a configurable batch size via batchCount and EvalDataSlice.getAccountEvalData.
  • Introduce EvalDataSlice.WriteEventsSkipNotifications and internal writeEvents to set SkipNotifications on all emitted PlatformEvents and honor custom batch size.
  • Update tests to cover SkipNotifications JSON behavior, default false omission, WriteEvents default SkipNotifications=false, and recovery chunking into 500-sized batches.
  • Ensure recovery publishing test verifies SkipNotifications=true and correct system counts and account/org propagation.
base/mqueue/platform_event.go
base/mqueue/platform_event_test.go
Add skip-publish advisory notification semantics so recovery recalc can mark advisories notified without emitting Kafka notifications.
  • Factor advisory_account_data.notified update logic into markAdvisoriesNotified helper.
  • Extend publishNewAdvisoriesNotification signature with skipPublish flag and implement branch that only marks notified and logs when skipping publish.
  • Keep the existing notification path intact, now reusing markAdvisoriesNotified after successful Kafka publish.
  • Modify evaluateAndStore to call publishNewAdvisoriesNotification when either instant notifications are enabled or the incoming event requests SkipNotifications, passing through the flag.
  • Add tests to verify skip_notifications through evaluateHandler and explicit publishNewAdvisoriesNotification usage, while updating existing tests for new function signature.
evaluator/notifications.go
evaluator/evaluate.go
evaluator/notifications_test.go

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

@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 1 issue, and left some high level feedback:

  • In writeEvents/writeEventsSkipNotifications, reqs[acc][start:end] assumes that request IDs exist for every account; for recovery EvalDataSlice entries where RequestID is empty this will leave reqs[acc] nil and can panic when slicing, so it would be safer to guard this access (e.g., use nil or an empty slice when reqs[acc] is nil or shorter than invs).
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In writeEvents/writeEventsSkipNotifications, reqs[acc][start:end] assumes that request IDs exist for every account; for recovery EvalDataSlice entries where RequestID is empty this will leave reqs[acc] nil and can panic when slicing, so it would be safer to guard this access (e.g., use nil or an empty slice when reqs[acc] is nil or shorter than invs).

## Individual Comments

### Comment 1
<location path="tasks/system_advisories_0_recovery/recovery.go" line_range="63-72" />
<code_context>
+	return nil
+}
+
+func getNonStaleBucket0InventoryIDs() ([]mqueue.EvalData, error) {
+	var inventoryAIDs []mqueue.EvalData
+	err := tasks.CancelableDB().Table("system_inventory si").
+		Select("si.inventory_id, si.rh_account_id, ra.org_id").
+		Joins("JOIN rh_account ra ON ra.id = si.rh_account_id").
+		Where("si.stale = false").
+		Where("satisfies_hash_partition('system_advisories'::regclass, ?, ?, si.rh_account_id)",
+			systemAdvisoriesPartitions, systemAdvisoriesRemainder).
+		Order("si.rh_account_id, si.id").
+		Scan(&inventoryAIDs).Error
+	if err != nil {
+		return nil, err
+	}
+	return inventoryAIDs, nil
+}
</code_context>
<issue_to_address>
**suggestion (performance):** Loading all bucket-0 inventory IDs into memory may not scale well for large accounts.

This function reads the entire non-stale bucket-0 result set into memory before processing. For large accounts this can create high memory usage and delay publishing until the full scan finishes. Since this is a recovery job that may run on production-scale data, consider streaming in batches (e.g., paginating by primary key and calling `WriteEventsSkipNotifications` per batch) to cap memory usage and begin sending events earlier.

Suggested implementation:

```golang
	var (
		totalCount      int
		lastInventoryID int64
	)

	for {
		inventoryAIDs, err := getNonStaleBucket0InventoryIDs(lastInventoryID, recoveryBatchSize)
		if err != nil {
			utils.LogError("err", err, "failed to load non-stale bucket-0 inventory IDs")
			return err
		}

		if len(inventoryAIDs) == 0 {
			break
		}

		err = mqueue.EvalDataSlice(inventoryAIDs).WriteEventsSkipNotifications(base.Context, evalWriter, recoveryBatchSize)
		if err != nil {
			utils.LogError("err", err, "sending recovery recalc messages failed")
			return err
		}

		totalCount += len(inventoryAIDs)

		// advance pagination cursor by the last inventory ID in this batch
		lastInventoryID = inventoryAIDs[len(inventoryAIDs)-1].InventoryID
	}

	utils.LogInfo("count", totalCount, "seconds", time.Since(start).Seconds(),
		"systems sent to recovery recalc with skip_notifications")
	return nil
}

```

```golang
func getNonStaleBucket0InventoryIDs(afterInventoryID int64, limit int) ([]mqueue.EvalData, error) {
	var inventoryAIDs []mqueue.EvalData

	db := tasks.CancelableDB().Table("system_inventory si").
		Select("si.inventory_id, si.rh_account_id, ra.org_id").
		Joins("JOIN rh_account ra ON ra.id = si.rh_account_id").
		Where("si.stale = false").
		Where("satisfies_hash_partition('system_advisories'::regclass, ?, ?, si.rh_account_id)",
			systemAdvisoriesPartitions, systemAdvisoriesRemainder).
		// paginate by primary key / stable ordering to allow streaming in batches
		Order("si.inventory_id").
		Limit(limit)

	if afterInventoryID > 0 {
		db = db.Where("si.inventory_id > ?", afterInventoryID)
	}

	if err := db.Scan(&inventoryAIDs).Error; err != nil {
		return nil, err
	}

	return inventoryAIDs, nil
}

```

1. This change assumes that `mqueue.EvalData` has an `InventoryID` field matching `si.inventory_id`; if the field is named differently, adjust `inventoryAIDs[len(inventoryAIDs)-1].InventoryID` accordingly.
2. If `system_inventory`'s stable pagination column is not `inventory_id`, replace both the `Order("si.inventory_id")` and `Where("si.inventory_id > ?", afterInventoryID)` with the correct primary key column.
3. If there are other call sites for `getNonStaleBucket0InventoryIDs`, update them to pass the `afterInventoryID` cursor and `limit` (e.g., usually `0` and `recoveryBatchSize`) or introduce a thin wrapper for backwards compatibility.
</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 tasks/system_advisories_0_recovery/recovery.go
@codecov-commenter

codecov-commenter commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.27273% with 42 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.12%. Comparing base (7ae4e4b) to head (52897ba).

Files with missing lines Patch % Lines
tasks/system_advisories_0_recovery/recovery.go 26.19% 30 Missing and 1 partial ⚠️
evaluator/notifications.go 73.68% 2 Missing and 3 partials ⚠️
base/mqueue/platform_event.go 81.81% 2 Missing and 2 partials ⚠️
main.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2289      +/-   ##
==========================================
- Coverage   59.27%   59.12%   -0.15%     
==========================================
  Files         148      149       +1     
  Lines        9488     9549      +61     
==========================================
+ Hits         5624     5646      +22     
- Misses       3276     3311      +35     
- Partials      588      592       +4     
Flag Coverage Δ
unittests 59.12% <52.27%> (-0.15%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@TenSt
TenSt force-pushed the stepan/RHINENG-26348-add-job-to-refill-0-partition branch from fc6e383 to 52897ba Compare July 30, 2026 17:26
@MichaelMraka MichaelMraka self-assigned this Jul 31, 2026
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.

3 participants