Skip to content

Conversation

@adityachoudhari26
Copy link
Contributor

@adityachoudhari26 adityachoudhari26 commented Sep 26, 2025

Summary by CodeRabbit

  • New Features
    • Faster startup by preloading resources into in-memory components.
  • Refactor
    • Unified initialization flow across workspace, selectors, and repositories using preloaded resources.
    • Removed factory-based creation in favor of constructor-based setup.
  • Performance
    • Reduced runtime database queries during initialization for improved responsiveness and stability.
  • Chores
    • Removed unused utility dependencies to simplify the codebase.

No changes to user-facing APIs or behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 26, 2025

Walkthrough

The in-memory resource initialization was refactored to accept externally provided FullResource[] data. Repository factory creation was removed. Selector create methods now require initialEntities. Workspace now fetches initial resources once, then passes them into selector and repository constructors during load.

Changes

Cohort / File(s) Summary
In-memory repository
apps/event-queue/src/repository/in-memory/resource.ts
Removed DB-backed initialization and static factory create(workspaceId). Constructor now solely uses provided initialEntities. Unused imports removed.
In-memory selectors
apps/event-queue/src/selector/in-memory/deployment-resource.ts, apps/event-queue/src/selector/in-memory/environment-resource.ts
static create signatures updated to accept (workspaceId, initialEntities: FullResource[]). Initialization now seeds internal state from initialEntities instead of querying DB; initial match computation retained. Minor import cleanup.
Workspace wiring
apps/event-queue/src/workspace/workspace.ts
Added getInitialResources(id) to fetch and shape FullResource[]. createSelectorManager and createRepository now accept and pass initialResources. Workspace.load retrieves initialResources and wires them into selectors and repository.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor App
    participant Workspace
    participant DB
    participant SelectorMgr
    participant DepSel as InMemoryDeploymentResourceSelector
    participant EnvSel as InMemoryEnvironmentResourceSelector
    participant Repo as InMemoryResourceRepository

    App->>Workspace: load(workspaceId)
    Workspace->>DB: getInitialResources(workspaceId)
    DB-->>Workspace: FullResource[] initialResources

    Workspace->>SelectorMgr: createSelectorManager(initialResources)
    activate SelectorMgr
    SelectorMgr->>DepSel: create(workspaceId, initialResources)
    DepSel-->>SelectorMgr: instance (seeded)
    SelectorMgr->>EnvSel: create(workspaceId, initialResources)
    EnvSel-->>SelectorMgr: instance (seeded)
    deactivate SelectorMgr

    Workspace->>Repo: new InMemoryResourceRepository({ initialEntities: initialResources })
    Repo-->>Workspace: repository instance

    Note over DepSel,EnvSel: Initial match computation runs against provided initialEntities
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

A hop, a skip, I preload the hay,
No more burrowing DBs today.
Seeds in paw, I cache the fields,
Selectors bloom as logic yields.
With tidy nests of in-memory light,
I twitch my nose—startup’s right! 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title concisely and accurately summarizes the primary change of the pull request, which is to improve performance by loading initial resources only once rather than multiple times from the database.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch load-initial-resources-once

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
apps/event-queue/src/selector/in-memory/environment-resource.ts (1)

62-77: Guard against stale metadata in seeded resources

initialEntities are now the only source of resource data when seeding this selector. Before this change we always pulled fresh rows (including metadata) from the DB inside create(), but now the selector trusts whatever array the caller supplies. If a consumer accidentally hands us entities that weren’t derived from the latest DB state, we’ll insert outdated entries into computedEnvironmentResource and start returning inconsistent matches. Either add a defensive refresh (e.g., fetch metadata here when the caller doesn’t supply it) or assert that every entity includes current metadata so we fail fast instead of persisting incorrect rows.

apps/event-queue/src/repository/in-memory/resource.ts (1)

19-24: Avoid persisting mismatched in-memory state

We now accept initialEntities from the outside and immediately mirror them to the DB on writes. If the caller seeds the repository with stale or partially loaded resources, our mutations will happily overwrite canonical rows with that stale data. Consider enforcing that initialEntities originate from a trusted loader (or refreshing from the DB during construction) so we can guarantee the in-memory cache is consistent before we start writing back. At minimum, validate the shape/version of each entity before storing it.

apps/event-queue/src/selector/in-memory/deployment-resource.ts (1)

62-77: Guard against stale metadata in seeded resources

Same concern as the environment selector: we no longer hit the DB for resource state when seeding. If initialEntities are stale or missing metadata, we’ll recompute computedDeploymentResource rows with incorrect data and return wrong matches. Please add a validation/refresh step so we can trust the data we persist.

🧹 Nitpick comments (1)
apps/event-queue/src/workspace/workspace.ts (1)

50-81: Ensure initial resource snapshot stays in sync

We’re now building the single source of truth for initialResources here. If other startup paths call Workspace.load before metadata or resource tables settle, we risk propagating incomplete data to both selectors and the in-memory repository. Consider wrapping this fetch in a transaction (or version check) to guarantee a consistent snapshot before we pass it around.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fd9c724 and 93713fe.

📒 Files selected for processing (4)
  • apps/event-queue/src/repository/in-memory/resource.ts (1 hunks)
  • apps/event-queue/src/selector/in-memory/deployment-resource.ts (3 hunks)
  • apps/event-queue/src/selector/in-memory/environment-resource.ts (3 hunks)
  • apps/event-queue/src/workspace/workspace.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript with explicit types (prefer interfaces for public APIs)
Import styles: Use named imports, group imports by source (std lib > external > internal)
Consistent type imports: import type { Type } from "module"
Prefer async/await over raw promises
Handle errors explicitly (use try/catch and typed error responses)

Files:

  • apps/event-queue/src/selector/in-memory/deployment-resource.ts
  • apps/event-queue/src/workspace/workspace.ts
  • apps/event-queue/src/selector/in-memory/environment-resource.ts
  • apps/event-queue/src/repository/in-memory/resource.ts

⚙️ CodeRabbit configuration file

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

Files:

  • apps/event-queue/src/selector/in-memory/deployment-resource.ts
  • apps/event-queue/src/workspace/workspace.ts
  • apps/event-queue/src/selector/in-memory/environment-resource.ts
  • apps/event-queue/src/repository/in-memory/resource.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (CLAUDE.md)

Formatting: Prettier is used with @ctrlplane/prettier-config

Files:

  • apps/event-queue/src/selector/in-memory/deployment-resource.ts
  • apps/event-queue/src/workspace/workspace.ts
  • apps/event-queue/src/selector/in-memory/environment-resource.ts
  • apps/event-queue/src/repository/in-memory/resource.ts
🧠 Learnings (1)
📚 Learning: 2025-06-24T23:56:54.799Z
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.

Applied to files:

  • apps/event-queue/src/repository/in-memory/resource.ts
🧬 Code graph analysis (3)
apps/event-queue/src/selector/in-memory/deployment-resource.ts (1)
packages/events/src/kafka/events.ts (1)
  • FullResource (62-64)
apps/event-queue/src/workspace/workspace.ts (5)
packages/events/src/kafka/events.ts (1)
  • FullResource (62-64)
apps/event-queue/src/selector/in-memory/deployment-resource.ts (1)
  • InMemoryDeploymentResourceSelector (30-257)
apps/event-queue/src/selector/in-memory/environment-resource.ts (1)
  • InMemoryEnvironmentResourceSelector (30-260)
apps/event-queue/src/repository/repository.ts (1)
  • WorkspaceRepository (55-133)
apps/event-queue/src/repository/in-memory/resource.ts (1)
  • InMemoryResourceRepository (15-60)
apps/event-queue/src/selector/in-memory/environment-resource.ts (1)
packages/events/src/kafka/events.ts (1)
  • FullResource (62-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: Lint
  • GitHub Check: Typecheck

Comment on lines +66 to +80
.groupBy((row) => row.resource.id)
.map((group) => {
const [first] = group;
if (first == null) return null;
const { resource } = first;
const metadata = Object.fromEntries(
group
.map((r) => r.resource_metadata)
.filter(isPresent)
.map((m) => [m.key, m.value]),
);
return { ...resource, metadata };
})
.value()
.filter(isPresent);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: metadata lookup uses wrong property name

row.resource_metadata will always be undefined—Drizzle returns camelCase keys (row.resourceMetadata). As written, we drop every metadata row and seed selectors/repositories with empty metadata. That breaks any selector predicates relying on metadata and risks wiping metadata when the in-memory repository writes back. Please swap this to row.resourceMetadata.
Apply the following diff:

-          .map((r) => r.resource_metadata)
+          .map((r) => r.resourceMetadata)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.groupBy((row) => row.resource.id)
.map((group) => {
const [first] = group;
if (first == null) return null;
const { resource } = first;
const metadata = Object.fromEntries(
group
.map((r) => r.resource_metadata)
.filter(isPresent)
.map((m) => [m.key, m.value]),
);
return { ...resource, metadata };
})
.value()
.filter(isPresent);
.groupBy((row) => row.resource.id)
.map((group) => {
const [first] = group;
if (first == null) return null;
const { resource } = first;
const metadata = Object.fromEntries(
group
.map((r) => r.resourceMetadata)
.filter(isPresent)
.map((m) => [m.key, m.value]),
);
return { ...resource, metadata };
})
.value()
.filter(isPresent);
🤖 Prompt for AI Agents
In apps/event-queue/src/workspace/workspace.ts around lines 66 to 80, the code
reads row.resource_metadata which is always undefined because Drizzle returns
camelCase keys; replace usages of row.resource_metadata with
row.resourceMetadata so metadata entries are correctly collected (update the
.map and any related filters to use row.resourceMetadata and ensure
isPresent/type checks still apply).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is straight up wrong lol

@adityachoudhari26 adityachoudhari26 merged commit 040b66f into main Sep 26, 2025
6 checks passed
@adityachoudhari26 adityachoudhari26 deleted the load-initial-resources-once branch September 26, 2025 23:01
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