Repository navigation
Conversation
Prefetch existing stub integrations in one find({ _parentId: { $in } }) before the
loop instead of a findOne per source integration, matching the batching pattern
already used for existingTargetIntegrations just above.
👷 Deploy request for dashboard-v2-novu-staging pending review.Visit the deploys page to approve it
|
- build the map with first-occurrence-wins (Map.set would otherwise keep the last) - register stubs created inside the loop so a later iteration reuses them, matching what the per-iteration findOne did
|
Pushed a correctness follow-up after re-reviewing my own diff:
Behaviour should now be equivalent to the original for every input, not just the common one. |
|
Hi @yoo-minho did you had a chance to see that the unit tests connected to this usecase are passing? |
The N+1 fix replaces the per-iteration integrationRepository.findOne with a single batched integrationRepository.find (_parentId: $in). Update the unit test to mock that new query on the re-promotion path and drop the now-unused findOne stub. Verified all specs in this file pass.
|
Good catch — thanks for checking. You're right to push on this: the previous spec would not have passed on the re-promotion case. The fix swaps the per-iteration Just pushed a commit that:
I verified by transpiling the usecase and running all six scenarios in Happy to add an assertion on |
|
@scopsy friendly ping on this one — I think it's ready, but let me know if anything is still open on your side. To close the loop on your question: yes, the unit tests connected to this usecase pass. The catch was real — the batched read I introduced wasn't covered by the existing positional mocks ( Current state:
Happy to rebase or split this differently if that helps it land — just say the word. And if you'd rather not take it, that's completely fine too; I'd just like to stop it from sitting in limbo. |
|
Closing this to keep my open PR count down — it has been sitting well past this repo's usual review turnaround, and I would rather not leave unsolicited changes cluttering the queue. The change is self-contained and still applies; happy to reopen if a maintainer wants to take a look. |
What changed? Why was the change needed?
SyncAgentToEnvironmentUseCasecalledintegrationRepository.findOne(...)once per source integration inside aforloop — an N+1 query.This prefetches the existing stub integrations in a single
find({ _parentId: { $in: [...] } })before the loop and looks them up from aMap, mirroring the batching pattern already used a few lines above forexistingTargetIntegrations.Behaviour is unchanged — each source integration has a distinct
_parentId, so a single snapshot before the loop is sufficient; only the per-iteration query is removed.The N+1 was surfaced by a static-analysis tool (fixearly, which flags sequential
awaitof DB calls inside loops) and verified by hand. This description was drafted with LLM assistance.@codesmith-botwith what you need. Autofix is disabled.Greptile Summary
This PR reduces repeated integration lookups during agent environment sync. The main changes are:
_parentId$inquery.stubByParentIdmap for reuse inside the source-link loop.Confidence Score: 5/5
Safe to merge with minimal risk.
The change is localized to one API use case and preserves the previous reuse/create behavior while removing the N+1 repository call.
No files require special attention.
T-Rex Logs
What T-Rex did
Important Files Changed
Sequence Diagram
sequenceDiagram participant UseCase as SyncAgentToEnvironment participant AgentLinks as AgentIntegrationRepository participant Integrations as IntegrationRepository participant DB as MongoDB UseCase->>AgentLinks: load source and target links UseCase->>Integrations: find source integrations by source link ids UseCase->>Integrations: find existing target stubs where _parentId in source ids Integrations->>DB: single batched query DB-->>Integrations: existing stub integrations Integrations-->>UseCase: stubs loop each source link UseCase->>UseCase: resolve stub from stubByParentId map alt stub missing UseCase->>Integrations: create target stub integration UseCase->>UseCase: cache new stub by parent id end UseCase->>AgentLinks: create or revive target agent integration link endReviews (2): Last reviewed commit: "fix: preserve findOne first-match semant..." | Re-trigger Greptile
Greptile Summary
Eliminates an N+1 database query in
SyncAgentToEnvironmentUseCaseby prefetching all relevant stub integrations in a single batchedfindbefore the source-link loop, then resolving each lookup from an in-memoryMapinstead of issuing afindOneper iteration.candidateSourceIdscomputation and afind({ _parentId: { $in: [...] } })call before the loop, mirroring the existing batching pattern forexistingTargetIntegrations.stubByParentIdMap with first-match semantics and updates it after each new stub is created so later loop iterations can reuse freshly-created stubs — exactly preserving the originalfindOnebehaviour.findOnestub and adds anonThirdCallstub for the new batched prefetch in the re-promotion scenario.Confidence Score: 5/5
Important Files Changed
Sequence Diagram
sequenceDiagram participant UC as SyncAgentToEnvironment participant IR as IntegrationRepository participant DB as MongoDB Note over UC,DB: Before the loop (new batch prefetch) UC->>IR: "find({ _parentId: { $in: sourceIds }, _environmentId, _organizationId })" IR->>DB: single batched query DB-->>IR: existingStubs[] IR-->>UC: existingStubs UC->>UC: build stubByParentId Map (first-match per _parentId) loop each sourceLink UC->>UC: stubByParentId.get(sourceIntegration._id) alt stub not found in map UC->>IR: create stub integration IR-->>UC: newStub UC->>UC: stubByParentId.set(sourceIntegration._id, newStub) end UC->>UC: createOrReviveLink for target agent endReviews (4): Last reviewed commit: "Merge branch 'next' into perf/sync-agent..." | Re-trigger Greptile