Skip to content

Fetch issues by queue state rather than in daily batches - #787

Open
nforro wants to merge 1 commit into
packit:mainfrom
nforro:fetcher
Open

Fetch issues by queue state rather than in daily batches#787
nforro wants to merge 1 commit into
packit:mainfrom
nforro:fetcher

Conversation

@nforro

@nforro nforro commented Aug 27, 2026

Copy link
Copy Markdown
Member

Maximum triage queue depth is controlled by QUEUE_DEPTH_THRESHOLD (currently 15). If the current queue depth is lower than the threshold, a cron job running every 15 minutes pushes issues from the CVE work to do filter up until the threshold. ymir_todo issues are unaffected by this and the triage_queue_todo queue is limited only by MAX_ISSUES (now lowered to 20).

Fixes https://redhat.atlassian.net/browse/PACKIT-5273.

@qodo-for-packit

Copy link
Copy Markdown

PR Summary by Qodo

Top up Jira issues based on triage queue depth

✨ Enhancement ⚙️ Configuration changes 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Top up automated CVE triage queues only when combined depth falls below 15.
• Run the automated fetcher every five minutes with a four-minute deadline.
• Preserve independent TODO ingestion while reducing its per-run MAX_ISSUES cap to 20.
Diagram

sequenceDiagram
    participant C as Cron Scheduler
    participant F as Jira Fetcher
    participant R as Redis Queues
    participant J as Jira API
    C->>F: Run every 5 minutes
    F->>R: Read combined depth
    R-->>F: Return queue depth
    alt Below threshold
        F->>J: Search CVE filter
        J-->>F: Return issues
        F->>R: Enqueue remaining capacity
    else At threshold
        F-->>C: Skip cycle
    end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Atomic Redis capacity reservation
  • ➕ Enforces a strict queue cap across concurrent producers.
  • ➕ Eliminates the gap between reading depth and pushing tasks.
  • ➖ Requires Lua or reservation bookkeeping and failure cleanup.
  • ➖ Adds complexity when the threshold is only a replenishment target.
  • ➖ Could unnecessarily constrain the independent TODO fetcher.

Recommendation: Keep the current depth-check-and-top-up approach because the threshold is a soft target for automated CVE intake, not a strict global cap. The dedicated threshold ConfigMap leaves TODO ingestion independent, while CronJob overlap prevention limits duplicate automated runs; atomic reservation is only warranted if exceeding the target becomes operationally harmful.

Files changed (6) +128 / -12

Enhancement (1) +30 / -4
jira_issue_fetcher.pyThrottle issue pushes by current queue depth +30/-4

Throttle issue pushes by current queue depth

• Parses an optional queue depth threshold, sums both Redis triage queues, and skips searches when capacity is full. When capacity remains, it overrides the normal push limit with the number of available queue slots.

ymir/jira_issue_fetcher/jira_issue_fetcher.py

Tests (1) +87 / -2
test_jira_issue_fetcher.pyCover queue-aware fetcher behavior +87/-2

Cover queue-aware fetcher behavior

• Adds tests for threshold parsing, combined queue depth, push-limit precedence, full-queue skipping, and below-threshold top-ups. Updates the existing workflow expectation for the optional override argument.

ymir/jira_issue_fetcher/tests/unit/test_jira_issue_fetcher.py

Documentation (1) +4 / -1
jira-issue-fetcher.envDocument queue depth configuration +4/-1

Document queue depth configuration

• Updates the example MAX_ISSUES value and documents the optional combined triage queue depth threshold.

templates/jira-issue-fetcher.env

Other (3) +7 / -5
configmap-jira-issue-fetcher-env.ymlLower the shared per-run issue limit +4/-3

Lower the shared per-run issue limit

• Reduces MAX_ISSUES from 100 to 20 for both Jira fetcher jobs. Updates the stale-label comment to describe the two fetchers without assuming daily scheduling.

openshift/configmap-jira-issue-fetcher-env.yml

configmap-jira-issue-fetcher-filter-env.ymlSet the automated queue depth target +1/-0

Set the automated queue depth target

• Adds QUEUE_DEPTH_THRESHOLD=15 to the automated CVE filter configuration, enabling depth-based throttling only for that fetcher.

openshift/configmap-jira-issue-fetcher-filter-env.yml

cronjob-jira-issue-fetcher.ymlRun queue top-ups every five minutes +2/-2

Run queue top-ups every five minutes

• Changes the automated fetcher from a daily batch to a five-minute replenishment schedule. Shortens the job deadline to four minutes so runs finish before the next cycle.

openshift/cronjob-jira-issue-fetcher.yml

@qodo-for-packit

qodo-for-packit Bot commented Aug 27, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Queue top-up uses stale capacity ✗ Dismissed 🐞 Bug ≡ Correctness ⭐ New
Description
The main and todo CronJobs run on the same five-minute schedule, but the main fetcher measures
combined depth before Jira search and later enqueues against that stale allowance while the
independent todo job can add work meanwhile. As a result, the normal CVE batch can push the combined
backlog past QUEUE_DEPTH_THRESHOLD, defeating the PR's top-up control during routine concurrent
runs.
Code

ymir/jira_issue_fetcher/jira_issue_fetcher.py[R1049-1052]

+                async with redis_client(self.redis_url) as redis_conn:
+                    depth = await self._get_queue_depth(redis_conn)
+                logger.info(f"Triage queue depth: {depth} (threshold: {self.queue_depth_threshold})")
+                remaining = self.queue_depth_threshold - depth
Relevance

●●● Strong

A recent, closely matching precedent accepted serialization fixes for shared Redis check-then-act
races.

PR-#610

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The main fetcher samples both lists once and performs Jira search before the eventual LPUSH, while a
separately scheduled todo CronJob writes to one of those same lists under an independent concurrency
policy. The prior concurrency review also establishes the repository's need to serialize decisions
based on shared Redis state.

ymir/jira_issue_fetcher/jira_issue_fetcher.py[577-581]
ymir/jira_issue_fetcher/jira_issue_fetcher.py[1047-1064]
ymir/jira_issue_fetcher/jira_issue_fetcher.py[803-810]
openshift/cronjob-jira-issue-fetcher.yml[8-10]
openshift/cronjob-jira-issue-fetcher-todo.yml[8-10]
PR-#610

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The queue capacity is sampled before Jira search and is not reserved, so concurrent producers can invalidate `push_cap` before the main fetcher enqueues.

## Issue Context
Both Jira fetcher CronJobs run every five minutes. The todo fetcher intentionally remains unthrottled, but normal-flow insertion should atomically verify available combined capacity rather than consuming a stale allowance.

## Fix Focus Areas
- ymir/jira_issue_fetcher/jira_issue_fetcher.py[1047-1064]
- ymir/jira_issue_fetcher/jira_issue_fetcher.py[803-810]
- ymir/jira_issue_fetcher/tests/unit/test_jira_issue_fetcher.py[746-769]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Threshold disables consolidation fallback 🐞 Bug ☼ Reliability ⭐ New
Description
When the triage queues are full, run() returns before searching or calling
_process_consolidation_labels(), so the main fetcher's documented consolidation fallback is
disabled for every cycle at or above the threshold. If the todo poller misses or fails a
consolidation request, the fallback cannot recover it until the triage backlog drops below 15.
Code

ymir/jira_issue_fetcher/jira_issue_fetcher.py[R1053-1055]

+                if remaining <= 0:
+                    logger.info("Queue depth at/above threshold - skipping this cycle")
+                    return
Relevance

●●● Strong

Recent fetcher reviews accepted reliability fixes preserving processing across failures and
consolidation-related polling paths.

PR-#540
PR-#760

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed return occurs before search_issues, while consolidation is invoked only after search
and queue push. Repository deployment documentation explicitly identifies the main fetcher as the
slower fallback for consolidation labels.

ymir/jira_issue_fetcher/jira_issue_fetcher.py[1043-1069]
ymir/jira_issue_fetcher/jira_issue_fetcher.py[843-850]
openshift/README.md[131-135]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The queue-depth early return skips non-triage consolidation processing as well as queue insertion.

## Issue Context
The main fetcher is documented as a fallback processor for consolidation labels. At capacity, continue the search/consolidation path while disabling triage insertion, or separate consolidation handling from the throttled queue path.

## Fix Focus Areas
- ymir/jira_issue_fetcher/jira_issue_fetcher.py[1047-1067]
- ymir/jira_issue_fetcher/tests/unit/test_jira_issue_fetcher.py[746-754]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Deadline truncates Jira retries 🐞 Bug ☼ Reliability
Description
The new 240-second Job deadline is shorter than one Jira operation's existing retry budget:
_make_request_with_retries may perform four requests with 90-second timeouts plus backoff.
Kubernetes can therefore terminate a valid fetch cycle mid-retry or pagination, and the Job-level
deadline also prevents backoffLimit retries from recovering that cycle.
Code

openshift/cronjob-jira-issue-fetcher.yml[21]

+      activeDeadlineSeconds: 240  # 4 minutes max runtime (cron is */5, must not overlap)
Relevance

●● Moderate

Retry-budget concern is concrete, but the closest deadline precedent was undetermined rather than
clearly accepted.

PR-#540

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed CronJob line imposes a hard four-minute lifetime, while the fetcher permits four
90-second attempts for each Jira request and may make multiple paginated requests.
concurrencyPolicy: Forbid already serializes scheduled runs, so terminating at four minutes is not
necessary to prevent overlap.

openshift/cronjob-jira-issue-fetcher.yml[9-21]
ymir/jira_issue_fetcher/jira_issue_fetcher.py[152-163]
ymir/jira_issue_fetcher/jira_issue_fetcher.py[419-449]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CronJob's 240-second active deadline can expire before the fetcher's four 90-second Jira attempts and backoff complete, terminating valid work and preventing Job retries after the deadline.

## Issue Context
The five-minute schedule does not require each run to finish within five minutes because `concurrencyPolicy: Forbid` already prevents overlap. Either retain a deadline that covers the worst-case request/pagination path, or reduce the HTTP timeout/retry policy so it is guaranteed to fit within the Job deadline.

## Fix Focus Areas
- openshift/cronjob-jira-issue-fetcher.yml[9-21]
- ymir/jira_issue_fetcher/jira_issue_fetcher.py[152-163]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Fetcher schedule documentation is stale 🐞 Bug ⚙ Maintainability ⭐ New
Description
The CronJob now runs every five minutes, but the OpenShift deployment table still says it runs daily
at 08:00 UTC. This gives operators incorrect polling and load expectations for the production
manifest.
Code

openshift/cronjob-jira-issue-fetcher.yml[9]

+  schedule: "*/5 * * * *"  # Every 5 minutes — tops up the triage queue toward QUEUE_DEPTH_THRESHOLD
Relevance

●●● Strong

Recent OpenShift review accepted documentation updates when deployment behavior changed, including
fetcher configuration changes.

PR-#760
PR-#703

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The deployed manifest uses */5 * * * *, while the deployment table still lists 0 8 * * * and
describes a daily batch.

openshift/cronjob-jira-issue-fetcher.yml[8-10]
openshift/README.md[120-129]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The deployment README still documents the removed daily schedule.

## Issue Context
Update the main fetcher row and surrounding wording to describe five-minute queue-depth top-ups and the configured threshold.

## Fix Focus Areas
- openshift/README.md[120-129]
- openshift/README.md[135-135]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
⚠️ Tickets: not configured — ticket URL found in PR but could not be fetched — check ticket provider credentials
✅ Compliance rules (platform): 8 rules

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit 6bb59f4

Results up to commit 1cbca7b ⚖️ Balanced


🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Deadline truncates Jira retries 🐞 Bug ☼ Reliability
Description
The new 240-second Job deadline is shorter than one Jira operation's existing retry budget:
_make_request_with_retries may perform four requests with 90-second timeouts plus backoff.
Kubernetes can therefore terminate a valid fetch cycle mid-retry or pagination, and the Job-level
deadline also prevents backoffLimit retries from recovering that cycle.
Code

openshift/cronjob-jira-issue-fetcher.yml[21]

+      activeDeadlineSeconds: 240  # 4 minutes max runtime (cron is */5, must not overlap)
Relevance

●● Moderate

Retry-budget concern is concrete, but the closest deadline precedent was undetermined rather than
clearly accepted.

PR-#540

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed CronJob line imposes a hard four-minute lifetime, while the fetcher permits four
90-second attempts for each Jira request and may make multiple paginated requests.
concurrencyPolicy: Forbid already serializes scheduled runs, so terminating at four minutes is not
necessary to prevent overlap.

openshift/cronjob-jira-issue-fetcher.yml[9-21]
ymir/jira_issue_fetcher/jira_issue_fetcher.py[152-163]
ymir/jira_issue_fetcher/jira_issue_fetcher.py[419-449]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CronJob's 240-second active deadline can expire before the fetcher's four 90-second Jira attempts and backoff complete, terminating valid work and preventing Job retries after the deadline.

## Issue Context
The five-minute schedule does not require each run to finish within five minutes because `concurrencyPolicy: Forbid` already prevents overlap. Either retain a deadline that covers the worst-case request/pagination path, or reduce the HTTP timeout/retry policy so it is guaranteed to fit within the Job deadline.

## Fix Focus Areas
- openshift/cronjob-jira-issue-fetcher.yml[9-21]
- ymir/jira_issue_fetcher/jira_issue_fetcher.py[152-163]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread openshift/cronjob-jira-issue-fetcher.yml Outdated
@nforro

nforro commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

Comment thread ymir/jira_issue_fetcher/jira_issue_fetcher.py Outdated
Comment thread ymir/jira_issue_fetcher/jira_issue_fetcher.py Outdated
Comment thread openshift/cronjob-jira-issue-fetcher.yml Outdated
@qodo-for-packit

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 90e8177

@nforro

nforro commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

@qodo-for-packit

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 4155462

@lbarcziova lbarcziova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

just 2 notes, otherwise looks great!

Comment thread openshift/configmap-jira-issue-fetcher-env.yml
Comment thread openshift/cronjob-jira-issue-fetcher.yml Outdated
lbarcziova
lbarcziova previously approved these changes Aug 27, 2026

@lbarcziova lbarcziova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this LGTM, thanks!

I am just thinking how this will work together with #746 , which pushes directly to triage queue, cc @jpodivin

Signed-off-by: Nikola Forró <nforro@redhat.com>
Assisted-by: Claude Sonnet 5 via Claude Code
@nforro

nforro commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

I am just thinking how this will work together with #746 , which pushes directly to triage queue, cc @jpodivin

It should work fine, just the issues pushed from sweeps will have priority over regular issues.

@nforro

nforro commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

Forgot to update the OpenShift README for 15 minutes interval.

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