Skip to content

feat(worker): Subscriber job bound lru cache#9814

Merged
scopsy merged 2 commits intonextfrom
cursor/subscriber-job-bound-lru-cache-0a2c
Jan 9, 2026
Merged

feat(worker): Subscriber job bound lru cache#9814
scopsy merged 2 commits intonextfrom
cursor/subscriber-job-bound-lru-cache-0a2c

Conversation

@scopsy
Copy link
Contributor

@scopsy scopsy commented Jan 9, 2026

What changed? Why was the change needed?

Implemented an LRU cache for fetching non-code-based workflows within SubscriberJobBoundUseCase. This change introduces caching for getWorkflow to reduce database load and improve performance for frequently accessed workflows, aligning with the caching mechanism recently added to run-job.usecase.ts.

Screenshots

N/A

Expand for optional sections

Related enterprise PR

Special notes for your reviewer

The LRU cache functionality is gated by the IS_LRU_CACHE_ENABLED feature flag, specifically for the worker-workflow component.


Slack Thread

Open in Cursor Open in Web

Improves performance by caching workflow data and reducing database calls.

Co-authored-by: dima <dima@novu.co>
@cursor
Copy link
Contributor

cursor bot commented Jan 9, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@github-actions
Copy link
Contributor

github-actions bot commented Jan 9, 2026

Hey there and thank you for opening this pull request! 👋

We require pull request titles to follow specific formatting rules and it looks like your proposed title needs to be adjusted.

Your PR title is: feat(worker): Subscriber job bound lru cache

Requirements:

  1. Follow the Conventional Commits specification
  2. As a team member, include Linear ticket ID at the end: fixes TICKET-ID or include it in your branch name

Expected format: feat(scope): Add fancy new feature fixes NOV-123

Details:

PR title must end with 'fixes TICKET-ID' (e.g., 'fixes NOV-123') or include ticket ID in branch name

@scopsy scopsy changed the title Subscriber job bound lru cache feat(worker): Subscriber job bound lru cache Jan 9, 2026
component: 'worker-workflow',
});

if (isFeatureFlagEnabled) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cursoragent similiar to run job use cae, we should check the payload source here to skip caching when it exists

Copy link
Contributor

@cursor cursor bot Jan 9, 2026

Choose a reason for hiding this comment

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

Done! I've updated the getWorkflow method to skip caching when a payload source exists, matching the pattern in run-job.usecase.ts:

  • Added source parameter to the method signature
  • Created isCacheEnabled = isFeatureFlagEnabled && !source to skip caching when source exists
  • Updated the call site to pass command.payload?.__source

Open in Cursor Open in Web

Learn more about Cursor Agents

@netlify
Copy link

netlify bot commented Jan 9, 2026

Deploy Preview for dashboard-v2-novu-staging canceled.

Name Link
🔨 Latest commit d9a3f3d
🔍 Latest deploy log https://app.netlify.com/projects/dashboard-v2-novu-staging/deploys/6960dd62d6f87a0008afb3bf

@scopsy scopsy marked this pull request as ready for review January 9, 2026 10:51
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

Walkthrough

The subscriber-job-bound use case has been enhanced with a caching mechanism for workflow lookups. An in-memory LRU cache with a 30-second TTL is introduced to store workflow data, along with an inflight request tracker to prevent duplicate concurrent fetches. The implementation is controlled by a feature flag (IS_LRU_CACHE_ENABLED) via FeatureFlagsService. The getWorkflow method signature is expanded to accept organizationId and source parameters, with cache behavior conditional on the feature flag and source presence. The method is now decorated with @Instrument. The constructor is updated to inject FeatureFlagsService as a dependency.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(worker): Subscriber job bound lru cache' clearly and concisely summarizes the main change: adding LRU cache functionality to the SubscriberJobBound use case.
Description check ✅ Passed The description provides relevant context about the caching implementation for workflow fetching, explains the motivation (reducing database load), and mentions the feature flag gating mechanism.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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: 0

🧹 Nitpick comments (2)
apps/worker/src/app/workflow/usecases/subscriber-job-bound/subscriber-job-bound.usecase.ts (2)

298-304: Consider feature flag performance impact (optional optimization).

The feature flag is checked on every getWorkflow invocation before cache lookup. While this ensures fresh flag values, it adds an async call on the hot path. Given that the workflow cache itself has a 30-second TTL, you might consider caching the feature flag value as well (with equal or shorter TTL) if profiling shows this is a bottleneck.

This is a minor optimization—the current implementation is correct and may be sufficient for your load patterns.


37-42: Consider event-driven cache invalidation for workflow updates if 30s staleness is unacceptable.

The workflow cache uses TTL-only invalidation (30-second window). While InvalidateCacheService exists elsewhere in the codebase for event-driven invalidation, the template cache here relies solely on expiration. If workflow updates during active execution require immediate invalidation, consider integrating InvalidateCacheService to invalidate cached templates on update events.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7488c61 and d9a3f3d.

📒 Files selected for processing (1)
  • apps/worker/src/app/workflow/usecases/subscriber-job-bound/subscriber-job-bound.usecase.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write concise, technical TypeScript code with accurate examples
Use descriptive variable names with auxiliary verbs (isLoading, hasError)
Add blank lines before return statements
Import motion components from 'motion/react' instead of 'motion-react'

**/*.{ts,tsx}: Write concise, technical TypeScript code with accurate examples
Use functional and declarative programming patterns; avoid classes
Prefer iteration and modularization over code duplication, minimize code duplication as possible
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Structure files: exported component, subcomponents, helpers, static content, types
Don't leave comments in code, unless they explain something complex and not trivial
Don't use nested ternaries
Favor named exports for components
Use TypeScript for all code; prefer interfaces over types
In front end code, use types over interfaces
Use functional components with TypeScript types
Use the "function" keyword for pure functions
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements
Add blank lines before return statements
When importing "motion-react" package, import it from "motion/react"

Files:

  • apps/worker/src/app/workflow/usecases/subscriber-job-bound/subscriber-job-bound.usecase.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use functional and declarative programming patterns; avoid classes

Files:

  • apps/worker/src/app/workflow/usecases/subscriber-job-bound/subscriber-job-bound.usecase.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Favor named exports for components

Files:

  • apps/worker/src/app/workflow/usecases/subscriber-job-bound/subscriber-job-bound.usecase.ts
**

📄 CodeRabbit inference engine (.cursor/rules/novu.mdc)

Use lowercase with dashes for directories and files (e.g., components/auth-wizard)

Files:

  • apps/worker/src/app/workflow/usecases/subscriber-job-bound/subscriber-job-bound.usecase.ts
⏰ 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). (5)
  • GitHub Check: E2E test API / Test E2E
  • GitHub Check: Validate OpenAPI
  • GitHub Check: Unit test backend services (@novu/worker)
  • GitHub Check: Analyze (typescript)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
apps/worker/src/app/workflow/usecases/subscriber-job-bound/subscriber-job-bound.usecase.ts (4)

9-9: LGTM: Clean import additions.

The new imports for FeatureFlagsService, FeatureFlagsKeysEnum, and LRUCache are properly sourced and necessary for the caching implementation.

Also applies to: 23-23, 31-31


55-56: LGTM: Proper dependency injection.

The FeatureFlagsService is correctly added to the constructor following NestJS dependency injection patterns.


85-90: LGTM: Proper parameter passing to getWorkflow.

The call site correctly passes organizationId and source parameters needed for feature flag evaluation and cache eligibility determination.


284-340: Cache key design is correct and requires no changes.

The cache key ${environmentId}:${_id} is sufficient for unique identification. MongoDB ObjectIds are globally unique, and the repository's findById method confirms this by querying only _id and _environmentId without organizationId. The organizationId parameter is appropriately used for feature flag authorization context, not for cache keying. The design intentionally separates data retrieval concerns from authorization context.

@scopsy scopsy merged commit f8754a4 into next Jan 9, 2026
38 of 39 checks passed
@scopsy scopsy deleted the cursor/subscriber-job-bound-lru-cache-0a2c branch January 9, 2026 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants