-
Notifications
You must be signed in to change notification settings - Fork 12.9k
fix: address livechat race condition in agent assignment with locking #37776
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: develop
Are you sure you want to change the base?
Conversation
|
Looks like this PR is not ready to merge, because of the following issues:
Please fix the issues and try again If you have any trouble, please check the PR guidelines |
🦋 Changeset detectedLatest commit: 47abb58 The changes in this PR will be included in the next version bump. This PR includes changesets to release 40 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughAdds per-agent distributed locking to omnichannel assignment: new agent lock fields and model methods, lock-aware agent selection, RoutingManager lock acquisition/release around takeInquiry, E2E test utilities and synchronization, and changes to tests and setup to avoid race conditions. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant RoutingManager
participant UsersModel as UsersModel (locks)
participant DB
participant Livechat
Client->>RoutingManager: takeInquiry(inquiry, agent)
RoutingManager->>UsersModel: acquireAgentLock(agentId)
UsersModel->>DB: atomic update (set agentLocked, agentLockedAt)
DB-->>UsersModel: modified / not modified
alt lock acquired
UsersModel-->>RoutingManager: true
RoutingManager->>Livechat: checkAgentBeforeTakeInquiry(agent)
Livechat-->>RoutingManager: ok / fail
alt preconditions ok
RoutingManager->>Livechat: perform takeInquiry(inquiry, agent)
Livechat->>DB: validate lockedAt matches
alt lockedAt matches
Livechat-->>RoutingManager: success (room assigned)
RoutingManager->>Livechat: emit agent-assigned, afterTakeInquiry, notify
else lockedAt mismatch
Livechat-->>RoutingManager: error-locked-at-mismatch
end
else preconditions fail
Livechat-->>RoutingManager: agent invalid -> set agent = null or rethrow
end
else lock not acquired
UsersModel-->>RoutingManager: false
RoutingManager-->>Client: error-agent-is-locked
end
RoutingManager->>UsersModel: releaseAgentLock(agentId)
UsersModel->>DB: unset agentLocked, agentLockedAt
DB-->>UsersModel: released
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
d445d02 to
72296a8
Compare
72296a8 to
09cb423
Compare
a0b19a1 to
ecdb94a
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #37776 +/- ##
===========================================
- Coverage 70.69% 70.64% -0.05%
===========================================
Files 3146 3146
Lines 108829 108829
Branches 19564 19588 +24
===========================================
- Hits 76933 76886 -47
- Misses 29896 29931 +35
- Partials 2000 2012 +12
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
dc37156 to
fcaedbe
Compare
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.
Actionable comments posted: 1
🧹 Nitpick comments (4)
packages/core-typings/src/ILivechatAgent.ts (1)
17-18: Consider adding JSDoc for the locking fields.The new optional fields support the agent locking mechanism to prevent over-assignment. While the implementation is correct, brief JSDoc comments would clarify their purpose and lifecycle for future maintainers.
Example:
openBusinessHours?: string[]; + /** Timestamp when the agent was locked for assignment operations */ agentLockedAt?: Date; + /** Indicates whether the agent is currently locked for assignment operations */ agentLocked?: boolean;apps/meteor/app/livechat/server/lib/RoutingManager.ts (1)
253-255: Consider usingMeteor.Errorfor consistency.Line 254 uses
new Error('error-agent-is-locked')while the rest of this file usesMeteor.Errorfor thrown errors (e.g., lines 88, 124, 145). UsingMeteor.Errorwould provide consistent error handling on the client side.if (options.clientAction && !options.forwardingToDepartment) { - throw new Error('error-agent-is-locked'); + throw new Meteor.Error('error-agent-is-locked'); }packages/models/src/models/Users.ts (2)
61-68: Hardcoded lock timeout should be a shared constant.The 5000ms timeout is hardcoded here and also appears as the default in
acquireAgentLock(line 803). Consider extracting this to a shared constant to ensure consistency and make future adjustments easier.+const AGENT_LOCK_TIMEOUT_MS = 5000; + const queryAvailableAgentsForSelection = (extraFilters = {}, isLivechatEnabledWhenAgentIdle?: boolean): Filter<IUser> => ({ ...queryStatusAgentOnline(extraFilters, isLivechatEnabledWhenAgentIdle), $and: [ { - $or: [{ agentLocked: { $exists: false } }, { agentLockedAt: { $lt: new Date(Date.now() - 5000) } }], + $or: [{ agentLocked: { $exists: false } }, { agentLockedAt: { $lt: new Date(Date.now() - AGENT_LOCK_TIMEOUT_MS) } }], }, ], });Then update line 803:
- async acquireAgentLock(agentId: IUser['_id'], lockTimeoutMs = 5000): Promise<boolean> { + async acquireAgentLock(agentId: IUser['_id'], lockTimeoutMs = AGENT_LOCK_TIMEOUT_MS): Promise<boolean> {
803-818: Consider adding an index for lock fields if high concurrency is expected.The lock acquisition query filters on
agentLockedandagentLockedAt. Under high load with many concurrent assignments, consider adding a partial index on these fields to improve query performance:{ key: { agentLocked: 1, agentLockedAt: 1 }, sparse: true }This is a low-priority optimization that may not be needed depending on deployment scale.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (11)
.changeset/cozy-melons-march.md(1 hunks)apps/meteor/app/livechat/server/lib/RoutingManager.ts(2 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts(1 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts(2 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts(1 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts(1 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts(1 hunks)apps/meteor/tests/end-to-end/api/livechat/04-dashboards.ts(1 hunks)packages/core-typings/src/ILivechatAgent.ts(1 hunks)packages/model-typings/src/models/IUsersModel.ts(1 hunks)packages/models/src/models/Users.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/end-to-end/api/livechat/04-dashboards.tspackages/model-typings/src/models/IUsersModel.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tspackages/core-typings/src/ILivechatAgent.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.tsapps/meteor/app/livechat/server/lib/RoutingManager.tspackages/models/src/models/Users.ts
**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use.spec.tsextension for test files (e.g.,login.spec.ts)
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
apps/meteor/tests/e2e/**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
apps/meteor/tests/e2e/**/*.spec.ts: All test files must be created inapps/meteor/tests/e2e/directory
Avoid usingpage.locator()in Playwright tests - always prefer semantic locators such aspage.getByRole(),page.getByLabel(),page.getByText(), orpage.getByTitle()
Usetest.beforeAll()andtest.afterAll()for setup/teardown in Playwright tests
Usetest.step()for complex test scenarios to improve organization in Playwright tests
Group related tests in the same file
Utilize Playwright fixtures (test,page,expect) for consistency in test files
Prefer web-first assertions (toBeVisible,toHaveText, etc.) in Playwright tests
Useexpectmatchers for assertions (toEqual,toContain,toBeTruthy,toHaveLength, etc.) instead ofassertstatements in Playwright tests
Usepage.waitFor()with specific conditions instead of hardcoded timeouts in Playwright tests
Implement proper wait strategies for dynamic content in Playwright tests
Maintain test isolation between test cases in Playwright tests
Ensure clean state for each test execution in Playwright tests
Ensure tests run reliably in parallel without shared state conflicts
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
apps/meteor/tests/e2e/**/*.{ts,spec.ts}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
apps/meteor/tests/e2e/**/*.{ts,spec.ts}: Store commonly used locators in variables/constants for reuse
Follow Page Object Model pattern consistently in Playwright tests
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
🧠 Learnings (14)
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/end-to-end/api/livechat/04-dashboards.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/end-to-end/api/livechat/04-dashboards.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,spec.ts} : Follow Page Object Model pattern consistently in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure clean state for each test execution in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/end-to-end/api/livechat/04-dashboards.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/page-objects/**/*.ts : Utilize existing page objects pattern from `apps/meteor/tests/e2e/page-objects/`
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Implement proper wait strategies for dynamic content in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/end-to-end/api/livechat/04-dashboards.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.beforeAll()` and `test.afterAll()` for setup/teardown in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.
Applied to files:
apps/meteor/tests/end-to-end/api/livechat/04-dashboards.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Applied to files:
apps/meteor/tests/end-to-end/api/livechat/04-dashboards.tsapps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : All test files must be created in `apps/meteor/tests/e2e/` directory
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts
🧬 Code graph analysis (7)
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
createConversation(103-123)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
createConversation(103-123)
apps/meteor/tests/end-to-end/api/livechat/04-dashboards.ts (1)
apps/meteor/tests/data/livechat/rooms.ts (1)
startANewLivechatRoomAndTakeIt(444-475)
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
createConversation(103-123)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
createConversation(103-123)
apps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
createConversation(103-123)
packages/models/src/models/Users.ts (1)
packages/core-typings/src/IUser.ts (1)
IUser(186-256)
⏰ 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). (12)
- GitHub Check: 🚢 Build Docker (arm64, rocketchat, coverage)
- GitHub Check: 🚢 Build Docker (amd64, authorization-service, queue-worker-service, ddp-streamer-service, cove...
- GitHub Check: 🚢 Build Docker (arm64, account-service, presence-service, stream-hub-service, omnichannel-tran...
- GitHub Check: 🚢 Build Docker (amd64, rocketchat, coverage)
- GitHub Check: 🚢 Build Docker (amd64, account-service, presence-service, stream-hub-service, omnichannel-tran...
- GitHub Check: 🚢 Build Docker (arm64, authorization-service, queue-worker-service, ddp-streamer-service, cove...
- GitHub Check: 🔎 Code Check / TypeScript
- GitHub Check: 🔎 Code Check / Code Lint
- GitHub Check: 🔨 Test Unit / Unit Tests
- GitHub Check: 🔨 Test Storybook / Test Storybook
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
🔇 Additional comments (15)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts (1)
33-35: LGTM! Sequential conversation creation prevents race conditions.The shift from parallel to sequential conversation creation aligns with the PR's agent locking mechanism, ensuring that agent assignment operations complete before the next one begins during test setup.
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts (2)
62-74: LGTM! Sequential setup prevents agent lock contention.The sequential conversation creation pattern ensures that agent assignment operations complete one at a time during test setup, avoiding the race conditions that this PR addresses.
308-320: LGTM! Consistent sequential pattern.This mirrors the Monitor role setup and maintains consistency across test suites while preventing race conditions during agent assignment.
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (1)
56-66: LGTM! Sequential creation avoids agent lock contention.The sequential conversation creation ensures that agent assignment operations don't conflict during test setup, consistent with the PR's locking mechanism.
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts (2)
96-115: LGTM! Sequential setup prevents race conditions.The sequential conversation creation pattern aligns with the PR's agent locking mechanism and ensures test setup completes without agent assignment conflicts.
117-128: LGTM! Data access pattern correctly reflects conversation structure.The updated access pattern (
conversation.data.room._idandconversation.data.visitor._id) correctly matches the return type ofcreateConversation, which nests room and visitor data under adataproperty..changeset/cozy-melons-march.md (1)
1-8: LGTM! Changeset accurately documents the fix.The changeset correctly identifies the affected packages and provides a clear description of the behavioral change that prevents agent over-assignment through locking.
apps/meteor/tests/end-to-end/api/livechat/04-dashboards.ts (1)
104-113: LGTM! Sequential room creation with helpful documentation.The shift from parallel to sequential room creation prevents agent lock contention, and the inline comment clearly explains the reasoning. The agent distribution logic (first 2 rooms to agent1, remaining to agent2) is correct and maintains test consistency.
apps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts (1)
74-106: Sequential conversation creation aligns with the new locking mechanism.The change from parallel
Promise.allto sequentialawaitcalls for conversation creation is appropriate given the new agent locking mechanism. This prevents potential test flakiness when multiple conversations compete for agent locks during setup. The data access pattern correctly uses thecreateConversationreturn structure.apps/meteor/app/livechat/server/lib/RoutingManager.ts (3)
250-257: Lock acquisition with graceful fallback is well-implemented.The lock acquisition correctly handles both the locked state and continues gracefully when
clientActionis false (automated routing). The conditional throw for client-initiated actions ensures users get proper feedback while automated processes can retry with different agents.
259-273: Proper lock cleanup on callback failure.The try-catch correctly releases the agent lock before either re-throwing (for client actions) or allowing the flow to continue with a null agent. This prevents lock leaks when precondition checks fail.
320-324: Lock release in finally block is correctly guarded.The conditional
if (agent?.agentId)properly handles cases where:
- Lock was never acquired (agent set to null at line 256)
- Callback failed and agent was nullified (line 271)
- Normal flow completion
This ensures lock release only when a lock was actually held.
packages/models/src/models/Users.ts (3)
803-835: Atomic lock operations are correctly implemented.The lock acquisition uses MongoDB's atomic
updateOnewith a conditional filter, which is the correct pattern for distributed locking. The release operation properly checksagentLocked: trueto avoid releasing locks held by other processes after timeout expiration.
795-798: Read consistency settings prevent stale reads.Adding
readConcern: { level: 'majority' }andreadPreference: 'primary'ensures that agent chat counts reflect committed data from the primary, preventing race conditions where stale secondary reads could allow over-assignment.
559-562: Locked agents are consistently excluded from all selection methods.The
queryAvailableAgentsForSelectionhelper is correctly applied togetNextLeastBusyAgent,getLastAvailableAgentRouted, andgetNextAgent, ensuring locked agents are excluded regardless of which routing method is used.
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.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
apps/meteor/app/livechat/server/lib/RoutingManager.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
apps/meteor/app/livechat/server/lib/RoutingManager.ts
🧬 Code graph analysis (1)
apps/meteor/app/livechat/server/lib/RoutingManager.ts (2)
packages/models/src/index.ts (2)
LivechatInquiry(176-176)LivechatRooms(178-178)apps/meteor/app/lib/server/lib/notifyListener.ts (1)
notifyOnLivechatInquiryChangedById(251-272)
⏰ 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). (2)
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
🔇 Additional comments (2)
apps/meteor/app/livechat/server/lib/RoutingManager.ts (2)
263-277: Proper lock cleanup on precondition failure.The guard around
livechat.checkAgentBeforeTakeInquirycorrectly releases the agent lock before re-throwing or setting agent to null. This prevents lock leakage when precondition checks fail.
288-325: Lock cleanup is guaranteed; lock timeout is properly implemented.The try-finally block correctly ensures the agent lock is released on all paths (success and exception). The object-based logging at lines 291 and 295 properly addresses the past review comments.
Lock timeout verification complete:
Users.acquireAgentLockimplements a 5-second default timeout with automatic expiration via MongoDB's$ltcomparison, preventing indefinite lock holding.Regarding line 303: throwing plain
Error('error-room-not-found')is consistent with the local convention in this file. Line 153 in the same code path (assignAgent) uses the identical pattern for invariant violations. Meteor.Error is reserved for domain-specific, user-facing errors elsewhere in this file (e.g., lines 88, 124, 145).
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.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/meteor/app/livechat/server/lib/RoutingManager.ts (1)
258-258: UseMeteor.Errorfor consistency.Line 258 throws a plain
Errorinstead ofMeteor.Error, which is inconsistent with other user-facing errors in this file (lines 88, 124, 145).
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
apps/meteor/app/livechat/server/lib/RoutingManager.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
apps/meteor/app/livechat/server/lib/RoutingManager.ts
🧠 Learnings (2)
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Applied to files:
apps/meteor/app/livechat/server/lib/RoutingManager.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.
Applied to files:
apps/meteor/app/livechat/server/lib/RoutingManager.ts
🧬 Code graph analysis (1)
apps/meteor/app/livechat/server/lib/RoutingManager.ts (3)
apps/meteor/lib/callbacks.ts (1)
callbacks(252-260)packages/models/src/index.ts (2)
LivechatInquiry(176-176)LivechatRooms(178-178)apps/meteor/app/lib/server/lib/notifyListener.ts (1)
notifyOnLivechatInquiryChangedById(251-272)
⏰ 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 Packages
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
| }), | ||
| ]); | ||
| const conversationA = await createConversation(api, { | ||
| agentId: `user1`, |
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.
I dont know if I'm following or not, but its an issue related to race conditions, and now the conversations are being in sequence instead of parallel, what is the motivation behind these changes?
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.
keeping the tests synchronous avoids the routing handler queuing conversations while the agent is locked, which would make the assertions flaky and dependent on timing rather than on the core logic. additionally, the queue handler can take up to 5 seconds to run and assign queued cases.
an alternative would be to explicitly wait for the queue handler to drain before resuming the assertions, but that would introduce extra timing coordination and likely similar (or even higher) execution cost. wdyt?
bd303c5
ad3b474 to
bd303c5
Compare
a5fb041 to
9ce7064
Compare
9ce7064 to
e3bcd54
Compare
9156415 to
bbeb7af
Compare
|
@coderabbitai pause |
✅ Actions performedReviews paused. |
9f798bc to
4237478
Compare
|
@coderabbitai resume |
✅ Actions performedReviews resumed. |
4237478 to
d84eaf8
Compare
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts (1)
33-43: Sequential execution improves stability but doesn't exercise concurrent scenario.The comment helpfully explains the CE environment limitation. However, consider:
- The sequential approach works around the race condition rather than testing the fix. If the agent locking is working correctly, concurrent creation should now be safe.
- The comment mentions CE-specific behavior—clarify if this test should behave differently in EE environments or if a separate test should validate concurrent assignment with the new locking mechanism.
Minor: Lines 37-38 use template literals (backticks) without interpolation. Consider using single quotes for plain strings:
agentId: 'user1'Based on coding guidelines, ensure tests run reliably in parallel without shared state conflicts.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts(3 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts(7 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts(2 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.ts(4 hunks)apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts(4 hunks)apps/meteor/tests/e2e/utils/omnichannel/rooms.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
- apps/meteor/tests/e2e/utils/omnichannel/rooms.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use.spec.tsextension for test files (e.g.,login.spec.ts)
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
apps/meteor/tests/e2e/**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
apps/meteor/tests/e2e/**/*.spec.ts: All test files must be created inapps/meteor/tests/e2e/directory
Avoid usingpage.locator()in Playwright tests - always prefer semantic locators such aspage.getByRole(),page.getByLabel(),page.getByText(), orpage.getByTitle()
Usetest.beforeAll()andtest.afterAll()for setup/teardown in Playwright tests
Usetest.step()for complex test scenarios to improve organization in Playwright tests
Group related tests in the same file
Utilize Playwright fixtures (test,page,expect) for consistency in test files
Prefer web-first assertions (toBeVisible,toHaveText, etc.) in Playwright tests
Useexpectmatchers for assertions (toEqual,toContain,toBeTruthy,toHaveLength, etc.) instead ofassertstatements in Playwright tests
Usepage.waitFor()with specific conditions instead of hardcoded timeouts in Playwright tests
Implement proper wait strategies for dynamic content in Playwright tests
Maintain test isolation between test cases in Playwright tests
Ensure clean state for each test execution in Playwright tests
Ensure tests run reliably in parallel without shared state conflicts
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
apps/meteor/tests/e2e/**/*.{ts,spec.ts}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
apps/meteor/tests/e2e/**/*.{ts,spec.ts}: Store commonly used locators in variables/constants for reuse
Follow Page Object Model pattern consistently in Playwright tests
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
🧠 Learnings (20)
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/page-objects/**/*.ts : Utilize existing page objects pattern from `apps/meteor/tests/e2e/page-objects/`
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,spec.ts} : Store commonly used locators in variables/constants for reuse
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,spec.ts} : Follow Page Object Model pattern consistently in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure clean state for each test execution in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.beforeAll()` and `test.afterAll()` for setup/teardown in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Implement proper wait strategies for dynamic content in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `page.waitFor()` with specific conditions instead of hardcoded timeouts in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Avoid using `page.locator()` in Playwright tests - always prefer semantic locators such as `page.getByRole()`, `page.getByLabel()`, `page.getByText()`, or `page.getByTitle()`
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Prefer web-first assertions (`toBeVisible`, `toHaveText`, etc.) in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-09-23T19:22:59.217Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 36987
File: apps/meteor/tests/e2e/page-objects/fragments/room-toolbar.ts:10-20
Timestamp: 2025-09-23T19:22:59.217Z
Learning: In Playwright e2e tests, prefer stable selectors like data-qa-id attributes over localized text in getByRole() or getByText() calls to prevent test failures when UI language changes. Test translations separately by validating actual text content after ensuring UI interactions work with stable selectors.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts
📚 Learning: 2025-12-16T17:29:45.163Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37834
File: apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-emoji.ts:12-22
Timestamp: 2025-12-16T17:29:45.163Z
Learning: In page object files under `apps/meteor/tests/e2e/page-objects/`, always import `expect` from `../../utils/test` (Playwright's async expect), not from Jest. Jest's `expect` has a synchronous signature and will cause TypeScript errors when used with web-first assertions like `toBeVisible()`.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
📚 Learning: 2025-11-05T20:53:57.761Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: apps/meteor/ee/server/startup/federation.ts:39-74
Timestamp: 2025-11-05T20:53:57.761Z
Learning: In Rocket.Chat (apps/meteor/app/settings/server/CachedSettings.ts), the settings.watchMultiple() method immediately invokes its callback with current values if all requested settings exist in the store, then continues watching for subsequent changes. It does not wait for a setting to change before the first invocation.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
🧬 Code graph analysis (4)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
waitForInquiryToBeTaken(125-144)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
waitForInquiryToBeTaken(125-144)
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (2)
createConversation(103-123)waitForInquiryToBeTaken(125-144)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (2)
createConversation(103-123)waitForInquiryToBeTaken(125-144)
⏰ 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 Packages
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
🔇 Additional comments (14)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts (2)
7-7: Good addition of synchronization utility.The
waitForInquiryToBeTakenimport enables proper wait strategies for inquiry state changes, aligning with Playwright best practices for handling dynamic content.
40-43: Proper synchronization ensures test reliability.The explicit wait for inquiry assignment prevents race conditions in the test itself and ensures the filtering UI operates on stable data.
As per coding guidelines, this implements proper wait strategies for dynamic content.
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (4)
5-5: LGTM! Necessary imports for proper test synchronization.The imports of
setSettingValueByIdandwaitForInquiryToBeTakenalign with the PR's goal of ensuring reliable test execution by enabling queue settings and waiting for inquiry assignment completion before assertions run.Also applies to: 8-8
27-33: LGTM! Queue settings properly configured for race condition fix.The
Livechat_waiting_queuesetting is explicitly required for the agent locking mechanism (per PR testing steps), and the shortOmnichannel_queue_delay_timeoutvalue of 1 second should improve test speed whilewaitForInquiryToBeTakenprovides sufficient retry buffer (10 seconds).As per coding guidelines, this follows proper test setup patterns with
test.beforeAll().
64-81: LGTM! Proper synchronization pattern implemented.The parallel conversation creation followed by
waitForInquiryToBeTakenensures all inquiries are assigned before test assertions run, addressing the previously flagged hardcoded delay issue. This polling-based approach (up to 10 seconds) provides reliable synchronization for the agent assignment flow.As per coding guidelines, this implements proper wait strategies for dynamic content instead of hardcoded timeouts.
88-98: LGTM! Comprehensive cleanup ensures test isolation.The
afterAllhook properly cleans up all resources and resets queue settings to their defaults, preventing side effects on subsequent tests. The use ofPromise.allfor parallel cleanup is efficient.As per coding guidelines, this ensures clean state for each test execution and maintains test isolation between test cases.
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.ts (4)
7-7: LGTM! Clean utility imports.The addition of
setSettingValueByIdandwaitForInquiryToBeTakenutilities improves test maintainability and reliability.Also applies to: 10-10
32-36: Cleaner settings configuration with utility function.Using
setSettingValueByIdis more maintainable than direct API calls. The configuration properly enables the waiting queue and sets a short delay timeout, which aligns with the PR's race condition fix scenario.
96-100: Essential synchronization for test stability with the locking fix.The
waitForInquiryToBeTakencall ensures all inquiries are fully assigned before the test proceeds. This is crucial for test reliability now that agent assignments involve per-agent locking (per the PR's race condition fix). Without this wait, the test could encounter flaky failures when asserting on inquiry states.
135-139: LGTM! Proper cleanup with consistent utility usage.Settings are correctly reset to their default values using the same utility function as setup, maintaining consistency and ensuring clean test state.
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts (4)
6-6: LGTM! Utility imports improve test quality.The imports of
setSettingValueByIdandwaitForInquiryToBeTakenprovide consistent, reusable helpers for settings management and proper synchronization strategies.Also applies to: 9-9
148-151: Excellent! Queue settings cleanup ensures test isolation.The addition of queue settings reset in
afterAllproperly addresses the previous review concern about test isolation. All settings modified inbeforeAllare now correctly restored.As per coding guidelines, maintain test isolation and ensure clean state for each test execution. Based on learnings, the previous concern about missing queue settings reset has been resolved.
37-40: Good refactor to use consistent setting utility.Using
setSettingValueByIdprovides a consistent API for settings management. The queue-related settings enable proper testing of the inquiry assignment flow, and correctly resettingOmnichannel_queue_delay_timeoutto its default value of 5 ensures clean test isolation.
117-118: No actionable issues found.The partial wait is correct: only agent-assigned conversations need synchronization. The unassigned conversation (visitorC) remains queued and can be safely closed without waiting—the endpoint imposes no inquiry state requirements.
d84eaf8 to
7fadcc3
Compare
7fadcc3 to
47abb58
Compare
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.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/meteor/app/livechat/server/lib/RoutingManager.ts (1)
255-330: Lock ownership is not tracked;releaseAgentLockcan unlock someone else’s lock if the lease expires.Right now
Users.acquireAgentLock()returns a boolean andUsers.releaseAgentLock(agentId)unsets unconditionally (seepackages/models/src/models/Users.tsLine 842-874). If instance A acquires the lock, stalls >5s, instance B re-acquires it, then instance A’sfinallywill callreleaseAgentLockand remove B’s lock—reintroducing the over-assignment race.Also: Line 263 should be
Meteor.Error(plainErrormay not preserve an error code for clientAction callers), and Line 307-308 is an implementation comment that can be dropped.
🤖 Fix all issues with AI agents
In @apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts:
- Around line 87-96: The cleanup in test.afterAll uses Promise.all but nests the
tag deletion array because [.map(...)] is not spread, so the tag delete promises
are treated as one element and not awaited; fix by spreading the mapped array of
delete promises (e.g., ...( [tagA, tagB, globalTag, sharedTag].map(tag =>
tag.delete()) )) or by concatenating the tag deletion promises into the outer
array so that Promise.all receives each promise individually; update the call
sites referencing test.afterAll, conversations, tagA/tagB/globalTag/sharedTag,
agent.delete, departmentA.delete, and setSettingValueById accordingly.
🧹 Nitpick comments (3)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
125-144: MakewaitForInquiryToBeTakenmore failure-explicit (status checks + clearer loop).Today it assumes a
200+ expected JSON shape; when the API returns a transient error (or non-JSON), this will fail with a low-signal exception and can mask the actual cause.Proposed patch
-export const waitForInquiryToBeTaken = async (api: BaseTest['api'], roomIds: string | string[], maxAttempts = 10, intervalMs = 1000) => { +export const waitForInquiryToBeTaken = async (api: BaseTest['api'], roomIds: string | string[], maxAttempts = 10, intervalMs = 1000) => { const ids = Array.isArray(roomIds) ? roomIds : [roomIds]; + if (maxAttempts < 1) { + throw new Error('maxAttempts must be >= 1'); + } + if (intervalMs < 0) { + throw new Error('intervalMs must be >= 0'); + } const checkInquiry = async (roomId: string) => { - for await (const [index] of Array(maxAttempts).entries()) { - const inquiry = await api.get('/livechat/inquiries.getOne', { roomId }); - const inquiryData = await inquiry.json(); + for (let attempt = 0; attempt < maxAttempts; attempt++) { + const res = await api.get('/livechat/inquiries.getOne', { roomId }); + if (res.status() !== 200) { + throw new Error(`Unable to fetch inquiry for room ${roomId} [http status: ${res.status()}]`); + } + const inquiryData = await res.json(); if (inquiryData.inquiry?.status !== 'queued') { return; } - if (index < maxAttempts - 1) { + if (attempt < maxAttempts - 1) { await new Promise((resolve) => setTimeout(resolve, intervalMs)); } } throw new Error(`Inquiry for room ${roomId} was not taken after ${maxAttempts * intervalMs}ms`); }; await Promise.all(ids.map(checkInquiry)); };apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts (1)
36-44: Avoid hardcoded “reset settings” values; snapshot-and-restore is safer for parallel e2e.Line 36-44 and Line 150-154 assume the prior state is
{ Livechat_waiting_queue: false, Omnichannel_queue_delay_timeout: 5, ... }. If another suite runs with different defaults (or suites run in parallel), this can leak state across files.Also applies to: 150-154
packages/models/src/models/Users.ts (1)
61-68: Good: selection paths now exclude locked agents; consider centralizing the lock-timeout constant.Right now the expiry window is duplicated (Line 65 vs default
lockTimeoutMs = 5000). A small constant/shared helper would keep query + lock semantics in sync.Also applies to: 598-602, 679-682, 975-975
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (12)
.changeset/cozy-melons-march.mdapps/meteor/app/livechat/server/lib/RoutingManager.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/utils/omnichannel/rooms.tsapps/meteor/tests/end-to-end/api/livechat/04-dashboards.tspackages/core-typings/src/ILivechatAgent.tspackages/model-typings/src/models/IUsersModel.tspackages/models/src/models/Users.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/meteor/tests/end-to-end/api/livechat/04-dashboards.ts
- apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats.spec.ts
- apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
packages/core-typings/src/ILivechatAgent.tsapps/meteor/tests/e2e/utils/omnichannel/rooms.tspackages/model-typings/src/models/IUsersModel.tsapps/meteor/app/livechat/server/lib/RoutingManager.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tspackages/models/src/models/Users.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
apps/meteor/tests/e2e/**/*.{ts,spec.ts}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
apps/meteor/tests/e2e/**/*.{ts,spec.ts}: Store commonly used locators in variables/constants for reuse
Follow Page Object Model pattern consistently in Playwright tests
Files:
apps/meteor/tests/e2e/utils/omnichannel/rooms.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use.spec.tsextension for test files (e.g.,login.spec.ts)
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
apps/meteor/tests/e2e/**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
apps/meteor/tests/e2e/**/*.spec.ts: All test files must be created inapps/meteor/tests/e2e/directory
Avoid usingpage.locator()in Playwright tests - always prefer semantic locators such aspage.getByRole(),page.getByLabel(),page.getByText(), orpage.getByTitle()
Usetest.beforeAll()andtest.afterAll()for setup/teardown in Playwright tests
Usetest.step()for complex test scenarios to improve organization in Playwright tests
Group related tests in the same file
Utilize Playwright fixtures (test,page,expect) for consistency in test files
Prefer web-first assertions (toBeVisible,toHaveText, etc.) in Playwright tests
Useexpectmatchers for assertions (toEqual,toContain,toBeTruthy,toHaveLength, etc.) instead ofassertstatements in Playwright tests
Usepage.waitFor()with specific conditions instead of hardcoded timeouts in Playwright tests
Implement proper wait strategies for dynamic content in Playwright tests
Maintain test isolation between test cases in Playwright tests
Ensure clean state for each test execution in Playwright tests
Ensure tests run reliably in parallel without shared state conflicts
Files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
🧠 Learnings (25)
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Implement proper wait strategies for dynamic content in Playwright tests
Applied to files:
apps/meteor/tests/e2e/utils/omnichannel/rooms.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `page.waitFor()` with specific conditions instead of hardcoded timeouts in Playwright tests
Applied to files:
apps/meteor/tests/e2e/utils/omnichannel/rooms.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Applied to files:
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts
Applied to files:
apps/meteor/tests/e2e/utils/omnichannel/rooms.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files
Applied to files:
apps/meteor/tests/e2e/utils/omnichannel/rooms.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/page-objects/**/*.ts : Utilize existing page objects pattern from `apps/meteor/tests/e2e/page-objects/`
Applied to files:
apps/meteor/tests/e2e/utils/omnichannel/rooms.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-19T12:32:29.696Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.
Applied to files:
.changeset/cozy-melons-march.md
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Applied to files:
apps/meteor/app/livechat/server/lib/RoutingManager.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.
Applied to files:
apps/meteor/app/livechat/server/lib/RoutingManager.tsapps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).
Applied to files:
apps/meteor/app/livechat/server/lib/RoutingManager.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.
Applied to files:
apps/meteor/app/livechat/server/lib/RoutingManager.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,spec.ts} : Store commonly used locators in variables/constants for reuse
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,spec.ts} : Follow Page Object Model pattern consistently in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure clean state for each test execution in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.beforeAll()` and `test.afterAll()` for setup/teardown in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Avoid using `page.locator()` in Playwright tests - always prefer semantic locators such as `page.getByRole()`, `page.getByLabel()`, `page.getByText()`, or `page.getByTitle()`
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Prefer web-first assertions (`toBeVisible`, `toHaveText`, etc.) in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts
📚 Learning: 2025-09-23T19:22:59.217Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 36987
File: apps/meteor/tests/e2e/page-objects/fragments/room-toolbar.ts:10-20
Timestamp: 2025-09-23T19:22:59.217Z
Learning: In Playwright e2e tests, prefer stable selectors like data-qa-id attributes over localized text in getByRole() or getByText() calls to prevent test failures when UI language changes. Test translations separately by validating actual text content after ensuring UI interactions work with stable selectors.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts
📚 Learning: 2025-12-16T17:29:45.163Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37834
File: apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-emoji.ts:12-22
Timestamp: 2025-12-16T17:29:45.163Z
Learning: In page object files under `apps/meteor/tests/e2e/page-objects/`, always import `expect` from `../../utils/test` (Playwright's async expect), not from Jest. Jest's `expect` has a synchronous signature and will cause TypeScript errors when used with web-first assertions like `toBeVisible()`.
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.tsapps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests
Applied to files:
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
🧬 Code graph analysis (7)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (2)
packages/core-services/src/index.ts (1)
api(55-55).github/actions/update-version-durability/index.js (1)
index(60-60)
packages/model-typings/src/models/IUsersModel.ts (1)
packages/core-typings/src/IUser.ts (1)
IUser(187-258)
apps/meteor/app/livechat/server/lib/RoutingManager.ts (2)
packages/models/src/index.ts (2)
LivechatInquiry(165-165)LivechatRooms(167-167)apps/meteor/app/lib/server/lib/notifyListener.ts (1)
notifyOnLivechatInquiryChangedById(230-249)
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
waitForInquiryToBeTaken(125-144)
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (2)
createConversation(103-123)waitForInquiryToBeTaken(125-144)
packages/models/src/models/Users.ts (1)
packages/core-typings/src/IUser.ts (1)
IUser(187-258)
apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts (1)
apps/meteor/tests/e2e/utils/omnichannel/rooms.ts (1)
waitForInquiryToBeTaken(125-144)
⏰ 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 Packages
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
🔇 Additional comments (13)
.changeset/cozy-melons-march.md (1)
1-8: LGTM! Changeset accurately documents the behavioral fix.The changeset properly lists all affected packages and provides a clear description of the race condition fix.
apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts (3)
5-5: LGTM! Proper imports for test utilities.The imports for
setSettingValueByIdandwaitForInquiryToBeTakenare correctly sourced and align with the PR's strategy to synchronize inquiry handling and prevent race conditions.Also applies to: 8-8
30-36: LGTM! Queue settings properly configured for test.The beforeAll hook correctly enables the waiting queue and reduces the delay timeout to speed up test execution. Response validation ensures settings are applied successfully.
76-79: LGTM! Proper synchronization prevents race conditions.The
waitForInquiryToBeTakencall ensures all inquiries are taken before the tests proceed, which is essential for preventing race conditions in the agent assignment flow that this PR addresses.packages/core-typings/src/ILivechatAgent.ts (1)
17-18: LGTM! Lock fields properly typed.The optional
agentLockedAtandagentLockedproperties are appropriately typed and support the distributed locking mechanism introduced in this PR.packages/model-typings/src/models/IUsersModel.ts (1)
141-142: LGTM! Well-defined locking method signatures.The
acquireAgentLockandreleaseAgentLockmethod signatures are properly typed with appropriate parameters and return types. The optionallockTimeoutMsparameter provides flexibility for configurable lock expiration.apps/meteor/tests/e2e/omnichannel/omnichannel-chat-transfers.spec.ts (5)
7-7: LGTM! Consistent utility imports.The imports for
setSettingValueByIdandwaitForInquiryToBeTakenare correctly added and follow the same pattern as other updated test files.Also applies to: 12-12
32-38: LGTM! Queue configuration properly set up for Monitor suite.The beforeAll hook correctly configures queue settings with appropriate timeout values for test execution.
86-89: LGTM! Essential synchronization for Monitor suite.The
waitForInquiryToBeTakencall ensures all three conversations have their inquiries taken before tests proceed, preventing race conditions in the assignment flow.
133-141: LGTM! Proper cleanup in Monitor suite afterAll.Queue settings are correctly reset to their default values, ensuring clean state for subsequent test runs.
286-292: LGTM! Manager suite follows consistent pattern.The Manager suite properly implements the same queue configuration, synchronization, and cleanup pattern as the Monitor suite, ensuring consistent test behavior across both suites.
Also applies to: 345-348, 371-378
apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-filters.spec.ts (1)
119-120: Good synchronization point after room creation.Waiting for the inquiries to leave
queuedbefore continuing should reduce flakiness in microservices/replica scenarios. Based on learnings, this is preferable to adding fixed sleeps.packages/models/src/models/Users.ts (1)
834-837: Nice: majority + primary read forgetAgentAndAmountOngoingChats.This aligns with the PR goal of avoiding stale reads in replica deployments.
| test.afterAll(async ({ api }) => { | ||
| await Promise.all([ | ||
| ...conversations.map((conversation) => conversation.delete()), | ||
| [tagA, tagB, globalTag, sharedTag].map((tag) => tag.delete()), | ||
| agent.delete(), | ||
| departmentA.delete(), | ||
| departmentB.delete(), | ||
| setSettingValueById(api, 'Livechat_waiting_queue', false), | ||
| setSettingValueById(api, 'Omnichannel_queue_delay_timeout', 5), | ||
| ]); |
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.
Fix nested array in Promise.all causing incomplete cleanup.
Line 90 creates a nested array structure inside Promise.all. The .map() call returns an array of promises [Promise, Promise, Promise, Promise], but this array itself is not spread, so Promise.all receives it as a single array element rather than individual promises. This means the tag deletion promises won't be awaited properly.
🔧 Proposed fix
test.afterAll(async ({ api }) => {
await Promise.all([
...conversations.map((conversation) => conversation.delete()),
- [tagA, tagB, globalTag, sharedTag].map((tag) => tag.delete()),
+ ...[tagA, tagB, globalTag, sharedTag].map((tag) => tag.delete()),
agent.delete(),
departmentA.delete(),
departmentB.delete(),
setSettingValueById(api, 'Livechat_waiting_queue', false),
setSettingValueById(api, 'Omnichannel_queue_delay_timeout', 5),
]);
});Alternatively, for better readability:
test.afterAll(async ({ api }) => {
await Promise.all([
...conversations.map((conversation) => conversation.delete()),
+ tagA.delete(),
+ tagB.delete(),
+ globalTag.delete(),
+ sharedTag.delete(),
- [tagA, tagB, globalTag, sharedTag].map((tag) => tag.delete()),
agent.delete(),
departmentA.delete(),
departmentB.delete(),
setSettingValueById(api, 'Livechat_waiting_queue', false),
setSettingValueById(api, 'Omnichannel_queue_delay_timeout', 5),
]);
});📝 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.
| test.afterAll(async ({ api }) => { | |
| await Promise.all([ | |
| ...conversations.map((conversation) => conversation.delete()), | |
| [tagA, tagB, globalTag, sharedTag].map((tag) => tag.delete()), | |
| agent.delete(), | |
| departmentA.delete(), | |
| departmentB.delete(), | |
| setSettingValueById(api, 'Livechat_waiting_queue', false), | |
| setSettingValueById(api, 'Omnichannel_queue_delay_timeout', 5), | |
| ]); | |
| test.afterAll(async ({ api }) => { | |
| await Promise.all([ | |
| ...conversations.map((conversation) => conversation.delete()), | |
| ...[tagA, tagB, globalTag, sharedTag].map((tag) => tag.delete()), | |
| agent.delete(), | |
| departmentA.delete(), | |
| departmentB.delete(), | |
| setSettingValueById(api, 'Livechat_waiting_queue', false), | |
| setSettingValueById(api, 'Omnichannel_queue_delay_timeout', 5), | |
| ]); | |
| }); |
🤖 Prompt for AI Agents
In @apps/meteor/tests/e2e/omnichannel/omnichannel-assign-room-tags.spec.ts
around lines 87 - 96, The cleanup in test.afterAll uses Promise.all but nests
the tag deletion array because [.map(...)] is not spread, so the tag delete
promises are treated as one element and not awaited; fix by spreading the mapped
array of delete promises (e.g., ...( [tagA, tagB, globalTag, sharedTag].map(tag
=> tag.delete()) )) or by concatenating the tag deletion promises into the outer
array so that Promise.all receives each promise individually; update the call
sites referencing test.afterAll, conversations, tagA/tagB/globalTag/sharedTag,
agent.delete, departmentA.delete, and setSettingValueById accordingly.
| async acquireAgentLock(agentId: IUser['_id'], lockTimeoutMs = 5000): Promise<boolean> { | ||
| const result = await this.updateOne( | ||
| { | ||
| _id: agentId, | ||
| $or: [{ agentLocked: { $exists: false } }, { agentLockedAt: { $lt: new Date(Date.now() - lockTimeoutMs) } }], | ||
| }, | ||
| { | ||
| $set: { | ||
| agentLocked: true, | ||
| agentLockedAt: new Date(), | ||
| }, | ||
| }, | ||
| ); | ||
|
|
||
| return result.modifiedCount > 0; | ||
| } | ||
|
|
||
| async releaseAgentLock(agentId: IUser['_id']): Promise<boolean> { | ||
| const result = await this.updateOne( | ||
| { | ||
| _id: agentId, | ||
| agentLocked: true, | ||
| }, | ||
| { | ||
| $unset: { | ||
| agentLocked: 1, | ||
| agentLockedAt: 1, | ||
| }, | ||
| }, | ||
| ); | ||
|
|
||
| return result.modifiedCount > 0; | ||
| } |
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.
🧩 Analysis chain
🏁 Script executed:
find . -name "Users.ts" -path "*/models/*" | head -5Repository: RocketChat/Rocket.Chat
Length of output: 187
🏁 Script executed:
rg -n "acquireAgentLock|releaseAgentLock" --type=ts -B 2 -A 10 | head -100Repository: RocketChat/Rocket.Chat
Length of output: 6495
🏁 Script executed:
rg -n "\.acquireAgentLock\s*\(|\.releaseAgentLock\s*\(" --type=ts -B 2 -A 3Repository: RocketChat/Rocket.Chat
Length of output: 1576
🏁 Script executed:
cat -n apps/meteor/app/livechat/server/lib/RoutingManager.ts | sed -n '240,340p'Repository: RocketChat/Rocket.Chat
Length of output: 4015
🏁 Script executed:
rg -n "releaseAgentLock|acquireAgentLock" --type=tsRepository: RocketChat/Rocket.Chat
Length of output: 891
Critical: releaseAgentLock(agentId) is unsafe without an ownership token—can unlock a newer lock acquired during function execution.
The lock is a short-lived lease (5000ms default timeout). If takeInquiry() executes longer than the timeout, another instance can acquire a new lock for the same agent. When the original instance's finally block calls releaseAgentLock(), it unconditionally releases the new lock, losing exclusivity.
Fix by having acquireAgentLock() return the agentLockedAt timestamp and requiring releaseAgentLock(agentId, agentLockedAt) to match it before unsetting.
As per SUP-945, in microservices deployments, Rocket.Chat instances could assign more chats to an agent than their configured maximum limit. For example, with 3 instances and an agent limit of 3 simultaneous chats, 4 chats could be assigned (3 on instance 1, 0 on instance 2, 1 on instance 3).
The race condition occurred because multiple instances simultaneously:
All instances saw the same initial count before any assignments completed, allowing over-assignment.
Proposed changes (including videos or screenshots)
Implemented agent locking during assignment to serialize operations per agent, combined with read consistency guarantees from MongoDB primary node.
Explicit locking on the users collection: in our case, transactions wouldn’t catch races unless we added artificial counters or dummy updates. A separate locks collection would add extra models, types, and indexes for little benefit. We chose two optional lock fields directly on the users collection because it’s simpler, aligns with our existing inquiry-locking pattern, and requires minimal changes.
Read consistency with replica sets: reads can hit secondaries and return stale data, causing an instance to see an outdated chat count even after acquiring a lock. To avoid this, we enforce
readPreference: primaryandreadConcern: majority, ensuring all reads reflect committed data from the primary node.Issue(s)
Steps to test or reproduce
Livechat_waiting_queuesettingFurther comments
Adding fields to a shared collection like users is risky. To minimize potential conflicts and make the intention clear, the fields are prefixed as
agentLockedandagentLockedAtinstead of generic names.Summary by CodeRabbit
Bug Fixes
New Features
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.