Skip to content

fix(jira): global_substream_cursor on issue streams — stop full re-sync every run - #1370

Merged
mitasovr merged 4 commits into
constructorfabric:mainfrom
mitasovr:claude/jira-global-substream-cursor
Jun 18, 2026
Merged

fix(jira): global_substream_cursor on issue streams — stop full re-sync every run#1370
mitasovr merged 4 commits into
constructorfabric:mainfrom
mitasovr:claude/jira-global-substream-cursor

Conversation

@mitasovr

@mitasovr mitasovr commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Problem

After #1316 (project auto-discovery) shipped, every jira sync became a ~2.5h / 2M+ record full re-sync — even nightly incremental runs. The Argo poll step times out before the Airbyte job finishes, so the enrich + dbt steps never run (jira silver stale, bronze_jira.jira_issue frozen at the last fully-committed run). Before #1316 a nightly run was ~80k records in ~3 min.

Root cause

#1316 made jira_issue and jira_issue_keys substreams of jira_project_discovery. The CDK kept their cursor state per-partition (keyed by project — 211 partitions, under the 10,000 cap that auto-switches to a global cursor), and that per-partition state did not persist: state/get returned {"states": []} for both streams. With no cursor, every sync re-pulled all projects from jira_start_date.

The issue substreams jira_issue_history/jira_comments/jira_worklogs were unaffected — their per-issue partition count (>130k) exceeds the 10k cap, so the CDK already auto-switched them to a global cursor, which persists fine.

Fix

global_substream_cursor: true on jira_issue and jira_issue_keys — one max(updated) cursor across all projects, persisted reliably.

Verified live (isolated read against virtuozzo Jira, full auto-discovery manifest)

  • state now persists: {"use_global_cursor": true, "state": {"updated": "2026-06-18 09:49"}, "parent_state": {"jira_project_discovery": {...}}} (was {"states": []})
  • first read (window from 2026-06-16): 5100 records
  • resume read with that state: 235 records (previously: full re-sync every run)

descriptor 2.0.0 → 2.0.1 so reconcile republishes the manifest (manifest-only edits don't ship without a version bump).

Note

The nightly jira-virtuozzo-sync cron is currently suspended on virtuozzo to stop the wasteful failing full-resyncs; it'll be re-enabled after this lands and a one-time full sync completes (after which runs are incremental again).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue in the Jira connector where incremental sync could repeatedly re-read data due to cursor state not persisting across substreams. The connector now uses a unified/global cursor for jira_issue and jira_issue_keys, improving reliability and preventing unnecessary re-syncs.
  • Chores
    • Updated the Jira connector version to reflect this patch-level cursor-handling fix.

@mitasovr
mitasovr requested a review from a team as a code owner June 18, 2026 11:22
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d78a138-cda0-44c1-b4e7-9cf849e2a374

📥 Commits

Reviewing files that changed from the base of the PR and between 423aff56f233c53d9f5e6dd3540effff4a14a74c and f1e7e4e.

📒 Files selected for processing (2)
  • src/ingestion/connectors/task-tracking/jira/connector.yaml
  • src/ingestion/connectors/task-tracking/jira/descriptor.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/ingestion/connectors/task-tracking/jira/descriptor.yaml
  • src/ingestion/connectors/task-tracking/jira/connector.yaml

📝 Walkthrough

Walkthrough

Two streams in the Jira connector YAML — jira_issue and jira_issue_keys — have global_substream_cursor: true added to their incremental_sync blocks, switching from per-partition to a single global cursor. The connector descriptor version is bumped from 2.0.0 to 2.0.1 with matching release notes.

Changes

Jira Connector: Global Substream Cursor Fix

Layer / File(s) Summary
Global substream cursor fix and version bump
src/ingestion/connectors/task-tracking/jira/connector.yaml, src/ingestion/connectors/task-tracking/jira/descriptor.yaml
global_substream_cursor: true is added under incremental_sync for both jira_issue and jira_issue_keys streams, with inline comments explaining the per-partition cursor non-persistence issue. The descriptor version advances to 2.0.1 with release notes to trigger reconcile republishing.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

Possibly related PRs

  • constructorfabric/insight#1283: Introduced jira_issue_keys as a lightweight parent stream in the same connector.yaml, directly preceding the cursor behavior change in this PR.
  • constructorfabric/insight#1310: Also bumps the Jira connector version in descriptor.yaml to force reconcile republishing after connector.yaml changes.
  • constructorfabric/insight#1316: Introduced project-partitioned substreams for jira_issue and jira_issue_keys, whose per-partition cursor non-persistence is the root cause addressed by this PR.

Suggested reviewers

  • mozhaev-dev

Poem

🐇 Hop, hop — no more re-reads from the start,
A global cursor now plays the smart part.
Per-partition states lost in the night,
One single cursor sets the sync right.
Version bumped, the reconciler sees,
The rabbit rests — full scans now cease! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main fix: addressing a full re-sync performance issue in JIRA by enabling global cursor state for issue streams.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
src/ingestion/connectors/task-tracking/jira/connector.yaml (1)

906-908: ⚡ Quick win

Make the sibling cursor-mode assumption explicit.

These comments rely on history/comments/worklogs crossing the CDK’s 10k partition auto-switch, but that is instance-size dependent. For Jira sources with fewer issue partitions, those streams may stay per-partition and hit the same non-persisted-state behavior; please verify the <10k case or set global_substream_cursor: true explicitly on those three issue substreams too.

Also applies to: 8106-8108

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ingestion/connectors/task-tracking/jira/connector.yaml` around lines 906
- 908, The comment assumes that history, comments, and worklogs substreams use
global cursors because they exceed the 10k partition cap, but this behavior is
instance-dependent. For Jira sources with fewer issue partitions, these three
substreams may remain per-partition and encounter non-persisted-state issues.
Either verify that the less-than-10k partition case works correctly for the
history, comments, and worklogs substreams, or explicitly add
global_substream_cursor: true to each of these three substreams (located at the
line references mentioned in the comment). Apply this same resolution to the
sibling configuration locations at lines 8106-8108.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/ingestion/connectors/task-tracking/jira/connector.yaml`:
- Around line 906-908: The comment assumes that history, comments, and worklogs
substreams use global cursors because they exceed the 10k partition cap, but
this behavior is instance-dependent. For Jira sources with fewer issue
partitions, these three substreams may remain per-partition and encounter
non-persisted-state issues. Either verify that the less-than-10k partition case
works correctly for the history, comments, and worklogs substreams, or
explicitly add global_substream_cursor: true to each of these three substreams
(located at the line references mentioned in the comment). Apply this same
resolution to the sibling configuration locations at lines 8106-8108.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dc97f31e-0ff1-49b1-a8e8-aa59032ed799

📥 Commits

Reviewing files that changed from the base of the PR and between c32821d and 423aff56f233c53d9f5e6dd3540effff4a14a74c.

📒 Files selected for processing (2)
  • src/ingestion/connectors/task-tracking/jira/connector.yaml
  • src/ingestion/connectors/task-tracking/jira/descriptor.yaml

…nc every run

constructorfabric#1316 made jira_issue and jira_issue_keys substreams of
jira_project_discovery. The CDK then kept their cursor state per-partition
(keyed by project — 211 partitions, under the 10k cap that auto-switches
to a global cursor), and that per-partition state did NOT persist: the
connection state stored `{"states": []}` for both. Every sync therefore
re-pulled all projects from jira_start_date — ~2.5h and 2M+ records per
run, so the Argo poll timed out and the enrich/dbt steps never ran (jira
silver stale; bronze jira_issue frozen at the last fully-committed run).
Before constructorfabric#1316, jira_issue was a plain incremental stream and a nightly run
was ~80k records in ~3 min.

Fix: set `global_substream_cursor: true` on both streams so they use a
single max(updated) cursor that persists (the same mechanism the
history/comments/worklogs substreams already use automatically, since
their per-issue partition count exceeds the 10k cap).

Verified live (isolated read against virtuozzo Jira, full manifest +
auto-discovery):
- state now persists as
  {"use_global_cursor": true, "state": {"updated": "..."},
   "parent_state": {"jira_project_discovery": {...}}}
- first read (window from 2026-06-16): 5100 records
- resume read with that state: 235 records (was: full re-sync every time)

descriptor 2.0.0 -> 2.0.1 so reconcile republishes the manifest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Roman Mitasov <Roman.Mitasov@constructor.tech>
@mitasovr
mitasovr force-pushed the claude/jira-global-substream-cursor branch from 423aff5 to f1e7e4e Compare June 18, 2026 12:50
@mitasovr
mitasovr merged commit 486b4e4 into constructorfabric:main Jun 18, 2026
12 checks passed
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