-
Notifications
You must be signed in to change notification settings - Fork 373
feat(web): add Syncing filter to Repositories table #1657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -137,6 +137,35 @@ export class BullMQClient { | |
| return jobs.flatMap((job) => job.id ? [job.id] : []); | ||
| } | ||
|
|
||
| async getSyncingJobIds<TName extends QueueName>( | ||
| spec: QueueSpec<TName>, | ||
| ): Promise<string[]> { | ||
| const jobs = await this.getQueue(spec).getJobs( | ||
| ["waiting", "waiting-children", "prioritized", "active"], | ||
| 0, | ||
| -1, | ||
| true, | ||
| ); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delayed retries missing from Syncing filterMedium Severity
Additional Locations (1)Reviewed by Cursor Bugbot for commit d3f819f. Configure here. |
||
|
|
||
| return jobs.flatMap((job) => job.id ? [job.id] : []); | ||
| } | ||
|
|
||
| async getSyncingRepoIds( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: Every page load with the Syncing filter now runs two full Prompt for AI agents |
||
| spec: QueueSpec<"repo-index">, | ||
| ): Promise<number[]> { | ||
| const jobs = await this.getQueue(spec).getJobs( | ||
| ["waiting", "waiting-children", "prioritized", "active"], | ||
| 0, | ||
| -1, | ||
| true, | ||
| ); | ||
|
|
||
| return jobs.flatMap((job) => { | ||
| const repoId = (job.data as { repoId?: number })?.repoId; | ||
| return typeof repoId === "number" ? [repoId] : []; | ||
| }); | ||
| } | ||
|
|
||
| async getJobLogs<TName extends QueueName>( | ||
| spec: QueueSpec<TName>, | ||
| jobId: string, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,7 +17,7 @@ const DEFAULT_PAGE_SIZE = 20; | |
| const pageSchema = z.coerce.number().int().positive(); | ||
| const sortBySchema = z.enum(["name", "indexedAt"]); | ||
| const sortOrderSchema = z.enum(["asc", "desc"]); | ||
| const statusSchema = z.enum(["failed", "warning"]); | ||
| const statusSchema = z.enum(["syncing", "failed", "warning"]); | ||
|
|
||
| type ReposPageProps = { | ||
| searchParams: Promise<{ | ||
|
|
@@ -44,16 +44,50 @@ export default authenticatedPage< | |
| const orderBy = sortBy === "indexedAt" | ||
| ? [{ indexedAt: sortOrder }, { id: "asc" as const }] | ||
| : [{ displayName: sortOrder }, { id: "asc" as const }]; | ||
| const failedJobIds = status === "all" | ||
| ? [] | ||
| : await getBullMQClient().getFailedJobIds(REPO_INDEX_QUEUE); | ||
| const bullMQClient = getBullMQClient(); | ||
| const [syncingJobIds, syncingRepoIds] = status === "syncing" | ||
| ? await Promise.all([ | ||
| bullMQClient.getSyncingJobIds(REPO_INDEX_QUEUE), | ||
| bullMQClient.getSyncingRepoIds(REPO_INDEX_QUEUE), | ||
| ]) | ||
| : [[], []]; | ||
| const failedJobIds = status === "failed" || status === "warning" | ||
| ? await bullMQClient.getFailedJobIds(REPO_INDEX_QUEUE) | ||
| : []; | ||
| const repositorySyncCounts = canRetry | ||
| ? await getRepositorySyncCounts() | ||
| : null; | ||
| const retryableCount = repositorySyncCounts | ||
| && !isServiceError(repositorySyncCounts) | ||
| ? repositorySyncCounts.failedCount + repositorySyncCounts.warningCount | ||
| : 0; | ||
| const getStatusWhereClause = (): Prisma.RepoWhereInput => { | ||
| switch (status) { | ||
| case "syncing": | ||
| return { | ||
| OR: [ | ||
| { latestIndexingJobId: { in: syncingJobIds } }, | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
|
||
| { id: { in: syncingRepoIds } }, | ||
| { | ||
| indexedAt: null, | ||
| firstIndexingJobFinishedAt: null, | ||
| }, | ||
| ], | ||
| }; | ||
|
cursor[bot] marked this conversation as resolved.
|
||
| case "failed": | ||
| return { | ||
| latestIndexingJobId: { in: failedJobIds }, | ||
| indexedAt: null, | ||
| }; | ||
| case "warning": | ||
| return { | ||
| latestIndexingJobId: { in: failedJobIds }, | ||
| indexedAt: { not: null }, | ||
|
Comment on lines
+64
to
+85
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Exclude failed jobs from the syncing fallback. The 🤖 Prompt for AI Agents |
||
| }; | ||
| default: | ||
| return {}; | ||
| } | ||
| }; | ||
| const where: Prisma.RepoWhereInput = { | ||
| orgId: org.id, | ||
| ...(search | ||
|
|
@@ -64,12 +98,7 @@ export default authenticatedPage< | |
| }, | ||
| } | ||
| : {}), | ||
| ...(status === "all" | ||
| ? {} | ||
| : { | ||
| latestIndexingJobId: { in: failedJobIds }, | ||
| indexedAt: status === "failed" ? null : { not: null }, | ||
| }), | ||
| ...getStatusWhereClause(), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Syncing rows show stale job statusMedium Severity Repositories included via Additional Locations (1)Reviewed by Cursor Bugbot for commit d3f819f. Configure here. |
||
| }; | ||
|
|
||
| const [repos, totalCount] = await Promise.all([ | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🌐 Web query:
For BullMQ 5.81.3, which Job property identifies a job created by Queue.upsertJobScheduler, and does Queue.getJobs(["waiting", "waiting-children", "prioritized", "active"]) return these jobs?💡 Result:
<search_synthesis>
In BullMQ, the
upsertJobSchedulermethod is a factory that creates jobs based on provided repeat options [1][2]. Jobs produced by a Job Scheduler do not have a specific property that identifies them as "scheduler-created" in a way that differentiates them from standard jobs added viaqueue.add, other than the fact that they are managed by the scheduler mechanism [1]. While you cannot assign a custom job ID to these jobs because the scheduler assigns a special ID to enforce repeat constraints, you can use the job'snameproperty to discriminate them from other jobs [1]. Regarding your second question,Queue.getJobs(["waiting", "waiting-children", "prioritized", "active"])will return jobs created byupsertJobSchedulerif they are currently in those specific states [3][4]. When a Job Scheduler creates a job, it is typically initially placed in thedelayedstate (waiting for its scheduled time) [5][1]. Once the scheduled time arrives, the job transitions into the standard job lifecycle (e.g.,waitingoractive), at which point it becomes visible togetJobswhen querying for those statuses [1][4].</search_synthesis>
<source_evidence>
Citations:
🏁 Script executed:
Repository: sourcebot-dev/sourcebot
Length of output: 25444
🤖 get_repo_knowledge executed:
get_repo_knowledge sourcebot-dev/sourcebot /tmp/coderabbit-repo-knowledge/sourcebot-dev-sourcebot-e3ed5267/architectureLength of output: 42640
🏁 Script executed:
Repository: sourcebot-dev/sourcebot
Length of output: 25179
🏁 Script executed:
Repository: sourcebot-dev/sourcebot
Length of output: 26925
🌐 Web query:
BullMQ 5.81.3 Job repeatJobKey scheduler-created job property Queue.upsertJobScheduler source💡 Result:
<search_synthesis>
In BullMQ (including version 5.81.3),
Queue.upsertJobScheduleris the primary method for managing recurring job schedules, effectively replacing older manual repeatable job methods [1]. TherepeatJobKeyis an internal property associated with repeatable jobs [2]. It acts as a unique identifier for the "meta" information that governs the repetition schedule, such as cron patterns or intervals [3][4]. When you useupsertJobScheduler, BullMQ internally generates or manages these repeatable keys to ensure that updates (e.g., changing a cron interval) modify the existing scheduler rather than creating duplicate, conflicting jobs [3][5]. Key details regarding your query include: 1. Scheduler-created Jobs: When you callupsertJobScheduler, it acts as a factory. It does not just add a single job; it creates a "scheduler" entry in Redis. This scheduler then automatically produces new jobs at the specified intervals [5][1]. These jobs are distinct from standard ad-hoc jobs and are managed via the internal repeatable key system [3]. 2. Property Context: TherepeatJobKeyproperty is primarily used by the library's internal logic (often found inclasses/repeat.ts) to track which jobs belong to which scheduling meta-job [6][2]. In job options, it is often seen as an internal metadata field [2]. You typically do not need to setrepeatJobKeymanually when usingupsertJobScheduler; the library handles this automatically [3]. 3. Source Context: The implementation forupsertJobScheduleris located within theQueueclass (typically insrc/classes/queue.ts), while the core scheduling logic that utilizes repeat keys resides in theJobSchedulerclass and theRepeatutility class [7][1]. If you are encountering issues with duplicate jobs or scheduling behavior, ensure you are using the samejobSchedulerIdstring consistently in yourupsertJobSchedulercalls, as this ID is what the library uses to perform the upsert (idempotent update) operation [8][5].</search_synthesis>
<source_evidence>
Citations:
🏁 Script executed:
Repository: sourcebot-dev/sourcebot
Length of output: 50379
🏁 Script executed:
Repository: sourcebot-dev/sourcebot
Length of output: 50379
🏁 Script executed:
Repository: sourcebot-dev/sourcebot
Length of output: 39474
🏁 Script executed:
Repository: sourcebot-dev/sourcebot
Length of output: 11283
Exclude BullMQ scheduler jobs from syncing lookups.
BullMQ exposes scheduler-created jobs through
job.repeatJobKey, andQueue.getJobsreturns them in the queried states. Both methods currently include these jobs. Filter out jobs withrepeatJobKeybefore mapping job IDs orrepoIdvalues. Otherwise, scheduled repository indexing can appear in the syncing filter.📍 Affects 1 file
packages/shared/src/bullmqClient.ts#L144-L144(this comment)packages/shared/src/bullmqClient.ts#L163-L165🤖 Prompt for AI Agents