-
Notifications
You must be signed in to change notification settings - Fork 56
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
[DTP-954, DTP-956] Add support for applying incoming state operations outside of STATE_SYNC sequence #1897
[DTP-954, DTP-956] Add support for applying incoming state operations outside of STATE_SYNC sequence #1897
Conversation
0893f79
to
e38b018
Compare
e38b018
to
2de8768
Compare
2de8768
to
c62f971
Compare
Warning Rate limit exceeded@VeskeR has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 28 minutes and 47 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. WalkthroughThe pull request introduces several enhancements across multiple files related to the LiveObjects functionality. Key changes include modifications to the Changes
Assessment against linked issues
Possibly related PRs
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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: 19
🧹 Outside diff range and nitpick comments (19)
src/plugins/liveobjects/objectid.ts (1)
5-9
: Consider adding more detailed documentation forObjectId
.While the class is marked as
@internal
, providing additional comments about its purpose and usage can enhance maintainability and assist other developers who may work with this code in the future.src/plugins/liveobjects/livecounter.ts (3)
84-90
: Use specific error codes for clearer error identificationIn the
_throwNoPayloadError
method, consider using a more specific error code instead of the generic50000
. This will help in accurately identifying and handling this particular error scenario.Apply this diff to specify a unique error code:
throw new this._client.ErrorInfo( `No payload found for ${op.action} op for LiveCounter objectId=${this.getObjectId()}`, - 50000, + 50101, // Example unique error code for missing payload 500, );
71-77
: Specify error codes and messages for unhandled operation actionsIn the default case of the
applyOperation
switch statement, throwing a generic error may not provide sufficient context. Consider defining specific error codes and more descriptive messages for unhandled actions.Apply this diff to enhance the error handling:
throw new this._client.ErrorInfo( `Invalid ${op.action} op for LiveCounter objectId=${this.getObjectId()}`, - 50000, + 50102, // Example unique error code for invalid operation action 500, );
10-17
: Document constructor parameters for clarityThe constructor now includes additional parameters
liveObjects
and_created
. Ensure these parameters are well-documented to aid developers in understanding their purpose and usage.src/plugins/liveobjects/syncliveobjectsdatapool.ts (1)
78-80
: Reevaluate Logging Severity Level Change toLOG_MAJOR
The logging severity level has been elevated from
LOG_MINOR
toLOG_MAJOR
for unsupported state object messages during SYNC. Consider whether this increase is appropriate, as it may result in more prominent logs and could potentially flood the logs if such messages are frequent. Ensure that this aligns with the logging policy and the importance of these messages.test/common/modules/live_objects_helper.js (3)
Line range hint
94-110
: Review the exposure of previously private methodsMethods such as
mapCreateOp
, previously prefixed with an underscore to indicate they were private (_mapCreateOp
), are now public. Consider whether making these methods public is necessary. If these methods are intended for internal use within the class, it might be better to keep them private to maintain encapsulation and prevent external misuse.
159-172
: Add unit tests for 'counterIncOp' methodThe
counterIncOp
method is a new addition that provides an operation to increment counters. To ensure its reliability, please add unit tests that cover various scenarios, including positive, negative, and zero increments.Would you like assistance in generating unit tests for this method?
Line range hint
174-196
: Improve error handling in 'stateRequest' methodThe
stateRequest
method throws a genericError
when the response is unsuccessful. Consider creating custom error classes or enriching the error message to provide more context, which can aid in debugging and handling specific error cases more effectively.src/plugins/liveobjects/liveobjectspool.ts (4)
90-90
: Fix typo in comment: 'wich' should be 'with'In the comment on line 90, there's a typographical error. The word "wich" should be corrected to "with" for clarity.
-// object wich such id already exists (we may have created a zero-value object before, or this is a duplicate *_CREATE op), +// object with such id already exists (we may have created a zero-value object before, or this is a duplicate *_CREATE op),
115-117
: Improve capitalization in comments for consistencyThe comments in lines 115-117 start with lowercase letters. For better readability and consistency with the rest of the codebase, consider starting comments with a capital letter.
-// we can receive an op for an object id we don't have yet in the pool. instead of buffering such operations, +// We can receive an op for an object id we don't have yet in the pool. Instead of buffering such operations,-// we create a zero-value object for the provided object id, and apply operation for that zero-value object. +// We create a zero-value object for the provided object id and apply the operation to that zero-value object.-// when we eventually receive a corresponding *_CREATE op for that object, its application will be handled by that zero-value object. +// When we eventually receive a corresponding *_CREATE op for that object, its application will be handled by the zero-value object.
92-92
: Implement subscription callbacks for applied operationsThere are
TODO
comments indicating that subscription callbacks should be invoked when an object operation is applied (lines 92 and 119). To ensure subscribers are notified of updates, consider implementing these callbacks.Would you like assistance in implementing the subscription callback mechanism for applied operations? I can help draft the necessary code or outline the steps required.
Also applies to: 119-119
84-85
: Avoid unnecessary variable assignmentThe variable
stateOperation
is used immediately after assignment and is not manipulated further. To streamline the code, you can accessstateMessage.operation
directly in the switch statement.-const stateOperation = stateMessage.operation; - -switch (stateOperation.action) { +switch (stateMessage.operation.action) {src/plugins/liveobjects/timeserial.ts (2)
69-70
: Correct verb tense in method documentationThe description in the
calculateTimeserial
method says "Calculate the timeserial object from a timeserial string." For consistency and correctness, it should be "Calculates the timeserial object from a timeserial string."Apply this diff to correct the documentation:
/** - * Calculate the timeserial object from a timeserial string. + * Calculates the timeserial object from a timeserial string. *
105-107
: Clarify the comparison method's return value in documentationIn the
_timeserialCompare
method's documentation, the description states:@returns 0 if the timeserials are equal, <0 if the first timeserial is less than the second, >0 if the first timeserial is greater than the second.
Consider rephrasing it for clarity:
@returns A negative number if this timeserial is less than the supplied timeserial, zero if they are equal, or a positive number if this timeserial is greater than the supplied timeserial.
Apply this diff to update the documentation:
* @param timeserialToCompare The timeserial to compare against. Can be a string or a Timeserial object. - * @returns 0 if the timeserials are equal, <0 if the first timeserial is less than the second, >0 if the first timeserial is greater than the second. + * @returns A negative number if this timeserial is less than the supplied timeserial, zero if they are equal, or a positive number if this timeserial is greater than the supplied timeserial. * @throws {@link BaseClient.ErrorInfo | ErrorInfo} if comparison timeserial is invalid. */src/plugins/liveobjects/livemap.ts (3)
226-236
: Handle potential missingop.data
propertiesIn the
_applyMapSet
method, after checking thatop.data
is notnil
, the code assumes that eitherop.data.objectId
orop.data.value
exists. If both are missing, it could lead to unexpected behavior. Although there's a prior check, consider adding explicit handling or comments to clarify this assumption.
252-275
: Handle missing entries gracefully in_applyMapRemove
In the
_applyMapRemove
method, ifexistingEntry
is not found, a new tombstoned entry is added. Confirm that this behavior aligns with the expected semantics, and consider whether additional checks or logs are necessary to track removals of non-existent keys.
126-166
: Review error handling inapplyOperation
The
applyOperation
method throws errors with a general error code and status. To aid debugging, consider using more specific error codes or messages that reflect the exact issue encountered.test/realtime/live_objects.test.js (2)
56-97
: Corrected test for handlingSTATE
ProtocolMessageThe test case has been appropriately updated to handle a
STATE
ProtocolMessage instead of aSTATE_SYNC
message. This ensures that the system's behavior is correctly validated when receivingSTATE
messages without the LiveObjects plugin.However, there is a small inconsistency:
Update inline comment for clarity
The comment on line 93 references a
STATE_SYNC
message, but the test is about processing aSTATE
message.Apply this diff to correct the comment:
- // regular message subscriptions should still work after processing STATE_SYNC message without LiveObjects plugin + // regular message subscriptions should still work after processing STATE message without LiveObjects plugin
921-942
: Ensure dynamic test descriptions are accurateIn the loop starting at line 921, test cases are dynamically generated using the descriptions from the
applyOperationsScenarios
array.
Verify that all test descriptions are accurate and meaningful, as they contribute to the readability of test results.
Consider adding checks to skip scenarios conditionally or provide informative messages if a scenario is skipped.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (13)
- scripts/moduleReport.ts (2 hunks)
- src/common/lib/client/realtimechannel.ts (1 hunks)
- src/plugins/liveobjects/livecounter.ts (1 hunks)
- src/plugins/liveobjects/livemap.ts (4 hunks)
- src/plugins/liveobjects/liveobject.ts (3 hunks)
- src/plugins/liveobjects/liveobjects.ts (6 hunks)
- src/plugins/liveobjects/liveobjectspool.ts (3 hunks)
- src/plugins/liveobjects/objectid.ts (1 hunks)
- src/plugins/liveobjects/statemessage.ts (1 hunks)
- src/plugins/liveobjects/syncliveobjectsdatapool.ts (4 hunks)
- src/plugins/liveobjects/timeserial.ts (1 hunks)
- test/common/modules/live_objects_helper.js (6 hunks)
- test/realtime/live_objects.test.js (6 hunks)
🧰 Additional context used
🪛 Biome
test/common/modules/live_objects_helper.js
[error] 198-198: The assignment should not be in an expression.
The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.(lint/suspicious/noAssignInExpressions)
🔇 Additional comments (34)
src/plugins/liveobjects/statemessage.ts (1)
130-130
: Improved documentation for theserial
property.The updated comment provides more specific information about the
serial
property, clarifying that it contains the origin timeserial for the state message. This enhancement improves code readability and helps developers understand the purpose of this property in the context of state synchronization.scripts/moduleReport.ts (2)
313-321
: New files added to LiveObjects plugin allowlist.Two new files have been added to the
allowedFiles
set in thecheckLiveObjectsPluginFiles
function:
- 'src/plugins/liveobjects/livecounter.ts'
- 'src/plugins/liveobjects/timeserial.ts'
This change aligns with the PR objectives of adding support for LiveCounter. However, we should ensure that these additions don't significantly impact the bundle size.
To verify the impact, please run the following script to check the contribution of these new files to the LiveObjects plugin bundle:
#!/bin/bash # Description: Check the contribution of new files to the LiveObjects plugin bundle node scripts/moduleReport.ts > report.txt grep "LiveObjects" report.txt grep -E "livecounter.ts|timeserial.ts" report.txt rm report.txt
9-9
: Verify the necessity of increasing the bundle size threshold.The
minimalUsefulRealtimeBundleSizeThresholdsKiB.raw
value has been increased from 100 to 101 KiB. While this is a minor change, it's important to ensure that this increase is justified by the new functionality added in this PR.Could you please provide more context on why this threshold needed to be increased? If possible, run the following script to check the current bundle size and see how close it is to this new threshold:
src/plugins/liveobjects/objectid.ts (2)
19-30
: Verify the correctness of error codes and consistency of error handling.Ensure that the error codes (
50000
) and status code (500
) used inErrorInfo
adhere to the project's error handling conventions. Consistent error codes facilitate better error tracking and debugging.
1-31
: LGTM!The overall implementation of the
ObjectId
class is clear and aligns with the intended functionality. Using a private constructor and a staticfromString
method effectively controls instantiation and ensures thatObjectId
instances are created correctly.src/plugins/liveobjects/liveobject.ts (4)
1-1
: Appropriate import statements addedThe addition of
BaseClient
andStateMessage
,StateOperation
imports is necessary for the new functionalities and types used in the class.Also applies to: 3-3
10-10
: Proper declaration of_client
as a protected memberDeclaring
_client
as a protected member allows subclasses ofLiveObject
to access the client if needed, enhancing extensibility.
20-20
: Correct initialization of_client
in the constructorInitializing
_client
withthis._liveObjects.getClient()
ensures that eachLiveObject
instance has access to the client, which is essential for its operations.
58-61
: Abstract methodapplyOperation
enforces consistent operation handlingAdding the abstract method
applyOperation(op: StateOperation, msg: StateMessage): void
mandates that all subclasses implement their own operation application logic, promoting consistent and reliable handling of state operations across different live object types.src/plugins/liveobjects/livecounter.ts (2)
26-28
: Good use of accessor methods for_created
state managementThe addition of
isCreated()
andsetCreated()
methods provides a clear interface for managing the_created
property, promoting encapsulation and maintainability.Also applies to: 33-35
40-78
: Verify all relevant operation actions are handledThe
applyOperation
method currently handlesCOUNTER_CREATE
andCOUNTER_INC
actions. Verify that there are no otherStateOperationAction
types that should be handled byLiveCounter
to ensure comprehensive operation processing.Run the following script to list all operation actions and check for any that might be applicable:
✅ Verification successful
All relevant operation actions are properly handled in
LiveCounter
.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: List all StateOperationAction enums and check for applicability to LiveCounter # List all StateOperationAction enum values rg 'export enum StateOperationAction' -A 20 # Search for usage of other actions with LiveCounter rg 'LiveCounter' -A 5Length of output: 14369
src/plugins/liveobjects/syncliveobjectsdatapool.ts (4)
2-2
: Optimize Import by Using Type-only Import forRealtimeChannel
Changing the import of
RealtimeChannel
to a type-only import optimizes the code by ensuring that the imported module is not included in the emitted JavaScript. This can reduce bundle size and prevent potential side effects from module loading.
4-4
: Add Necessary Import forLiveMap
The addition of the
LiveMap
import is necessary due to its usage in_createLiveMapDataEntry
. This ensures that theLiveMap.liveMapDataFromMapEntries
method is available.
63-64
: Update Logging Messages to Reflect Method Name ChangeThe logging messages have been updated to reflect the new method name
applyStateSyncMessages
, ensuring consistency in logs and easier traceability.
96-96
: Assigncreated
Property Directly in Object ConstructionThe
created
property is now assigned directly within thenewEntry
object construction. This improves code readability and ensures that all properties are initialized in one place.test/common/modules/live_objects_helper.js (4)
20-22
: Initialization of '_rest' in constructor is appropriateThe constructor correctly initializes
this._rest
with a newAblyRest
instance using the provided helper. This ensures that the instance has access to the REST client throughout its methods.
127-137
: Review the new 'mapRemoveOp' method for consistencyThe new
mapRemoveOp
method is well-defined. Ensure that this method aligns with the rest of the API and that corresponding unit tests are added to cover its functionality.
34-64
: Verify that all call sites of 'initForChannel' are updatedThe
initForChannel
method's signature has been changed by removing thehelper
parameter. Please ensure that all call sites of this method have been updated to match the new signature to prevent any runtime errors.Run the following script to find and review all usages of
initForChannel
:#!/bin/bash # Description: Find all call sites of 'initForChannel' and check for the correct signature. # Search for 'initForChannel' method calls in the codebase rg --glob '!test/common/modules/live_objects_helper.js' 'initForChannel\('
82-88
: Ensure 'createAndSetOnMap' method signature change is propagatedThe method
createAndSetOnMap
no longer accepts arest
parameter and relies onthis._rest
instead. Verify that any other uses of this method outside this file are updated accordingly.Run the following script to locate all usages of
createAndSetOnMap
:✅ Verification successful
✅ Verified: 'createAndSetOnMap' signature change is correctly propagated.
All usages of
createAndSetOnMap
outsidetest/common/modules/live_objects_helper.js
are confined to test files and are appropriately updated.
test/realtime/live_objects.test.js
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Find all call sites of 'createAndSetOnMap' to check for correct usage. # Search for 'createAndSetOnMap' method calls in the codebase rg --glob '!test/common/modules/live_objects_helper.js' 'createAndSetOnMap\('Length of output: 165
Script:
#!/bin/bash # Description: Corrected script to find all call sites of 'createAndSetOnMap' to verify usage. # Search for 'createAndSetOnMap' method calls in the codebase, excluding the specific test file rg --glob '!test/common/modules/live_objects_helper.js' 'createAndSetOnMap\('Length of output: 875
src/plugins/liveobjects/liveobjects.ts (4)
4-4
: Imports are appropriate for the new functionalityThe added import statements correctly bring in necessary types and classes (
API
,LiveCounterDataEntry
,SyncLiveObjectsDataPool
) used in the updated code.Also applies to: 10-10
107-107
: Confirm the change in_startNewSync
method callThe
onAttached
method now calls_startNewSync()
without parameters. Ensure that this is intentional and that the_startNewSync
method correctly handles undefinedsyncId
andsyncCursor
values.
187-189
: Validate type casting and ensure safe property accessIn the conditional block,
entry
is cast toLiveCounterDataEntry
to access thecreated
property. Confirm thatentry
is always of typeLiveCounterDataEntry
whenexistingObject
is an instance ofLiveCounter
to avoid potential runtime errors.
198-198
: Verify parameters forLiveCounter
constructorWhen instantiating a new
LiveCounter
, the parameters now includeentry.created
. Ensure that theLiveCounter
constructor is defined to acceptcreated
as the first argument and that the order of parameters matches the constructor definition to prevent initialization issues.src/plugins/liveobjects/liveobjectspool.ts (2)
66-67
: Verify the error code and status in the thrown exceptionWhen throwing an
ErrorInfo
exception for an unknown object type, ensure that the error code50000
and HTTP status500
are appropriate and consistent with the system's error handling conventions.Would you like to confirm that error code
50000
and status500
are the correct values to represent this exception in accordance with your error handling standards?
48-70
: Ensure exception handling when creating zero-value objectsIn
createZeroValueObjectIfNotExists
, an exception is thrown if an unknown object type is encountered. Ensure that this exception is properly handled in the calling methods to prevent unintended crashes.Would you like to verify that all calls to
createZeroValueObjectIfNotExists
are wrapped in try-catch blocks or that the exception propagates safely within the application's error handling framework?src/plugins/liveobjects/timeserial.ts (1)
145-145
:⚠️ Potential issueReview comparison logic when indices are undefined
In the
_timeserialCompare
method, when comparing indices, if eitherthis.index
orsecondTimeserial.index
isundefined
, the method returns0
, treating them as equal. This may lead to incorrect comparison results if one timeserial has an index and the other does not. Consider adjusting the comparison logic to handle cases where only one index is defined.Would you like to verify if this comparison logic aligns with the intended behavior? If not, we can adjust the comparison to ensure accurate ordering.
src/plugins/liveobjects/livemap.ts (2)
35-36
: Validate type changes forMapEntry
interfaceThe
MapEntry
interface has changedtimeserial
fromstring
toTimeserial
, anddata
is nowStateData | undefined
. Ensure that all usages ofMapEntry
across the codebase are updated to accommodate these changes, preventing type mismatches.Run the following script to identify usages of
MapEntry
:#!/bin/bash # Description: Find all usages of MapEntry and check for compatibility issues. # Expect: All usages should be compatible with the updated interface. rg 'MapEntry' -t typescript
181-203
: Confirm that_applyMapCreate
correctly handles entries without dataIn the
_applyMapCreate
method, when iterating overop.entries
, if an entry doesn't have associated data, it could lead to issues when passed to_applyMapSet
. Ensure that such cases are appropriately handled or rejected.Run the following script to check for entries without data:
test/realtime/live_objects.test.js (6)
39-40
: Proper instantiation ofLiveObjectsHelper
withnew
keywordThe
LiveObjectsHelper
is now correctly instantiated using thenew
keyword, which improves code clarity and aligns with standard JavaScript class instantiation practices.
Line range hint
268-307
: Ensure consistency in handlingSTATE_SYNC
messagesThe test simulates the reception of a
STATE_SYNC
message to verify thatgetRoot()
waits appropriately during aSTATE_SYNC
sequence. The implementation correctly injects aSTATE_SYNC
message with and without a cursor to simulate the start and end of the sequence.However, similar to the earlier comment, on line 307, the property
regionalTimeserial
is used again:regionalTimeserial: 'a@0-0',Confirm whether
regionalTimeserial
is the intended property.Refer to the verification script provided in the previous comment to check this usage.
Line range hint
311-660
: Validate nested map and counter initializationsThe test cases from lines 311 to 660 focus on verifying that the state object tree is built correctly from
STATE_SYNC
sequences, including nestedLiveMap
andLiveCounter
instances.
The assertions check for the correct types and values of nested objects, which is essential for ensuring data integrity.
The use of detailed
expect
statements enhances test clarity and effectiveness.
Line range hint
268-307
: Duplicate property name concernThe property
regionalTimeserial
appears in multiple places (lines 125 and 307). Since this property is not standard, there may be a typo or inconsistency.Also applies to: 125-125
125-125
: Confirm variable nameregionalTimeserial
On line 125, the property
regionalTimeserial
is introduced:regionalTimeserial: 'a@0-0',Ensure that
regionalTimeserial
is the correct property name. If the intended property isoriginalTimeserial
, consider updating it to prevent potential issues.Run the following script to check for the correct usage of
regionalTimeserial
in the codebase:✅ Verification successful
Confirmed
regionalTimeserial
is correctly usedThe property
regionalTimeserial
is consistently used across the codebase, confirming it is the correct property name.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Search for occurrences of 'regionalTimeserial' in the codebase. # Test: Find all instances. Expect: Only valid uses of 'regionalTimeserial' or confirm if 'originalTimeserial' is the correct term. rg 'regionalTimeserial'Length of output: 194
Script:
#!/bin/bash # Description: Search for occurrences of 'regionalTimeserial' in the codebase. rg 'regionalTimeserial'Length of output: 1119
493-919
: 🛠️ Refactor suggestionComprehensive testing of state operations
The additions from lines 493 to 919 introduce multiple test scenarios for applying state operations such as
MAP_CREATE
,MAP_SET
,MAP_DELETE
,COUNTER_CREATE
, andCOUNTER_INC
. These tests are crucial for validating the functionality of manipulating live objects through operations.
Enhance error handling in async functions
In the test scenario actions, consider adding try-catch blocks or handling rejected promises to ensure that any errors during asynchronous operations are caught and reported. This will make debugging test failures easier.
Optimize iteration over increments
In the
COUNTER_INC
test scenario, the for-loop starting at line 900 can be optimized by usingfor...of
for better readability:- for (let i = 0; i < increments.length; i++) { - const increment = increments[i]; + let i = 0; + for (const increment of increments) {Check for potential integer overflows
When incrementing counters with large values like
Number.MAX_SAFE_INTEGER
, ensure that the system correctly handles potential integer overflows.Run the following script to identify any potential issues with integer overflows in counter operations:
c62f971
to
5f59194
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- scripts/moduleReport.ts (2 hunks)
- test/common/modules/live_objects_helper.js (6 hunks)
- test/realtime/live_objects.test.js (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/moduleReport.ts
🧰 Additional context used
🪛 Biome
test/common/modules/live_objects_helper.js
[error] 198-198: The assignment should not be in an expression.
The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.(lint/suspicious/noAssignInExpressions)
test/realtime/live_objects.test.js
[error] 935-935:
await
is only allowed within async functions and at the top levels of modules.(parse)
[error] 945-945: Expected a statement but instead found ')'.
Expected a statement here.
(parse)
[error] 947-947: expected
,
but instead found}
Remove }
(parse)
🔇 Additional comments (15)
test/realtime/live_objects.test.js (7)
39-40
: LGTM: Improved LiveObjectsHelper initializationThe use of the
new
keyword for LiveObjectsHelper initialization enhances code clarity by explicitly showing that it's a constructor. This is a good practice and improves readability.
56-97
: LGTM: Comprehensive test for STATE message handlingThis updated test case effectively verifies that the system can handle STATE messages without breaking, even when the LiveObjects plugin is not provided. The test structure is clear and covers both the injection of the STATE message and the verification of normal functionality afterwards. This is a valuable test for ensuring system robustness.
Line range hint
268-331
: LGTM: Thorough test for handling STATE_SYNC sequencesThis updated test case effectively verifies the system's ability to handle multi-part STATE_SYNC sequences. It ensures that the getRoot() method correctly waits for the entire sequence to complete before resolving. The use of multiple injected messages simulates real-world scenarios, making this a valuable test for system reliability.
Line range hint
333-497
: LGTM: Comprehensive tests for state object tree and live object initializationThese new test cases significantly enhance the coverage of the live objects functionality. They thoroughly verify:
- Correct building of the state object tree from STATE_SYNC sequences
- Proper initialization of LiveCounter and LiveMap with values from STATE_SYNC sequences
- Handling of various scenarios including empty maps, referenced objects, and different data types
This comprehensive set of tests will help ensure the reliability and correctness of the live objects system.
498-923
: LGTM: Extensive test coverage for live object operationsThis substantial addition greatly enhances the test suite with:
- Well-structured helper functions for creating test fixtures
- Comprehensive test scenarios covering various operations (MAP_CREATE, MAP_SET, MAP_DELETE, COUNTER_CREATE, COUNTER_INC)
- Detailed setup, execution, and verification steps for each scenario
The tests are well-organized, cover a wide range of cases including edge cases, and will significantly contribute to ensuring the reliability of the live objects system. The use of scenarios and helper functions improves readability and maintainability of the test suite.
Line range hint
949-971
: LGTM: Valuable test for LiveObjects state modesThis new test case is an important addition that verifies the correct handling of LiveObjects state modes when attaching to a channel. It ensures that:
- The channel can be attached with LiveObjects state modes.
- The channel options are correctly set after attachment.
- The modes are properly reflected in the channel object.
This test will help maintain the integrity of the LiveObjects functionality with respect to channel attachment and mode setting.
🧰 Tools
🪛 Biome
[error] 935-935:
await
is only allowed within async functions and at the top levels of modules.(parse)
[error] 945-945: Expected a statement but instead found ')'.
Expected a statement here.
(parse)
[error] 947-947: expected
,
but instead found}
Remove }
(parse)
Line range hint
1-971
: Overall: Significant improvements to live objects test coverageThe changes to this file substantially enhance the test suite for live objects functionality. Key improvements include:
- More explicit initialization of LiveObjectsHelper.
- Updated and new test cases covering various scenarios like STATE and STATE_SYNC message handling, state object tree building, and live object initialization.
- Comprehensive test scenarios for different operations (MAP_CREATE, MAP_SET, MAP_DELETE, COUNTER_CREATE, COUNTER_INC).
- New test for attaching to channels with LiveObjects state modes.
These additions will greatly contribute to ensuring the reliability and correctness of the live objects system. However, there's a syntax error in the scenario execution loop that needs to be fixed (as noted in a previous comment).
After addressing the syntax error, this updated test file will provide robust coverage and significantly improve the quality assurance of the live objects functionality.
🧰 Tools
🪛 Biome
[error] 935-935:
await
is only allowed within async functions and at the top levels of modules.(parse)
[error] 945-945: Expected a statement but instead found ')'.
Expected a statement here.
(parse)
[error] 947-947: expected
,
but instead found}
Remove }
(parse)
test/common/modules/live_objects_helper.js (8)
20-22
: Proper Initialization of_rest
in the ConstructorInitializing
_rest
in the constructor ensures that the REST client is available throughout the class. This change enhances maintainability by centralizing the initialization.
Line range hint
34-70
: SimplifiedinitForChannel
Method Improves ReadabilityBy removing the unnecessary
helper
parameter and utilizingthis._rest
directly, theinitForChannel
method becomes cleaner and less coupled. This refactoring improves code readability and reduces potential errors related to parameter passing.
82-92
: RefactoredcreateAndSetOnMap
Method Enhances ClarityUpdating
createAndSetOnMap
to usethis._rest
directly and removing therest
parameter simplifies the method's interface. This change reduces dependencies and makes the method easier to use.
Line range hint
94-110
: PublicmapCreateOp
Method Increases FlexibilityConverting
_mapCreateOp
to a publicmapCreateOp
method allows for broader usage in tests and other helper methods. The implementation correctly constructs the map creation operation.
111-125
: Correct Implementation ofmapSetOp
MethodThe
mapSetOp
method accurately constructs the map set operation with the requiredkey
anddata
. This change ensures that map entries can be updated correctly.
127-140
: NewmapRemoveOp
Method Adds Delete FunctionalityThe addition of the
mapRemoveOp
method provides the ability to remove keys from a map. The method correctly constructs the remove operation, enhancing the helper's capabilities.
Line range hint
142-158
: Effective Handling of Optionalcount
incounterCreateOp
The
counterCreateOp
method appropriately checks ifcount
is provided and includes it in the operation if present. This allows for counters with initial values or defaulting to zero.
Line range hint
174-195
: Robust Error Handling instateRequest
MethodThe
stateRequest
method effectively handles both success and error cases when making REST requests. The error message provides detailed information, which is helpful for debugging.
5f59194
to
fb411b8
Compare
fb411b8
to
17c3f46
Compare
…nter This adds implementation for CRDT operations for LiveMap/LiveCounter classes to be able to handle incoming state operation messages. Resolves DTP-954
- add static LiveMap.liveMapDataFromMapEntries() method with logic previously used in SyncLiveObjectsDataPool. This method will be used in other places to create LiveMapData - minor refactoring and log improvements
… sync sequence Resolves DTP-956
- LiveObjectsHelper refactoring - timeserials format fix in existing LiveObjects tests (add seriesId part)
a9f9169
to
3960852
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: 6
🧹 Outside diff range and nitpick comments (10)
src/plugins/liveobjects/liveobject.ts (3)
20-20
: Consider adding error handling for client initializationWhile the client initialization is correctly placed, it might benefit from error handling in case
getClient()
returns null or undefined.- this._client = this._liveObjects.getClient(); + const client = this._liveObjects.getClient(); + if (!client) { + throw new Error('Failed to initialize LiveObject: Client is not available'); + } + this._client = client;
58-61
: Add comprehensive documentation for the abstract methodWhile the method signature is correct, it would benefit from detailed documentation explaining the purpose, parameters, and expected behavior for implementing classes.
/** * @internal + * Applies a state operation to the live object. + * @param op - The state operation to apply + * @param msg - The original state message containing the operation + * @throws {Error} If the operation type is not supported + * @throws {Error} If the operation cannot be applied in the current state */ abstract applyOperation(op: StateOperation, msg: StateMessage): void;
Line range hint
1-61
: Consider implementing operation validation in base classWhile the current design is solid, consider extracting common operation validation logic into the base class to promote code reuse and consistency across implementations. This could be done by adding protected validation methods that derived classes can use.
Example approach:
protected validateOperation(op: StateOperation, msg: StateMessage): void { if (!op.type) { throw new Error('Operation type is required'); } if (!this._isValidOperationType(op.type)) { throw new Error(`Unsupported operation type: ${op.type}`); } } protected abstract _isValidOperationType(type: string): boolean;src/plugins/liveobjects/livecounter.ts (1)
19-26
: Consider enhancing documentation for thezeroValue
factory methodWhile the method is well-implemented, consider adding documentation for the
isCreated
parameter to explain its significance and usage scenarios.Add parameter documentation:
/** * Returns a {@link LiveCounter} instance with a 0 value. * + * @param liveobjects - The LiveObjects instance managing this counter + * @param isCreated - Indicates whether this counter was created through a COUNTER_CREATE operation + * @param objectId - Optional identifier for the counter * @internal */test/common/modules/live_objects_helper.js (3)
20-22
: Add helper parameter validationConsider adding validation for the
helper
parameter to ensure it has the requiredAblyRest
method.constructor(helper) { + if (!helper?.AblyRest) { + throw new Error('helper must provide AblyRest method'); + } this._rest = helper.AblyRest({ useBinaryProtocol: false }); }
82-92
: Add parameter validation and JSDoc documentationConsider adding parameter validation and JSDoc documentation to improve the method's robustness and maintainability.
+/** + * Creates a new object and sets it on a map + * @param {string} channelName - The channel name + * @param {Object} opts - The options object + * @param {string} opts.mapObjectId - The ID of the map to set the object on + * @param {string} opts.key - The key to set the object under + * @param {Object} opts.createOp - The creation operation + * @returns {Promise<Object>} The creation result + */ async createAndSetOnMap(channelName, opts) { + if (!channelName) { + throw new Error('channelName is required'); + } const { mapObjectId, key, createOp } = opts ?? {}; + if (!mapObjectId || !key || !createOp) { + throw new Error('mapObjectId, key, and createOp are required'); + }
159-172
: Consider setting a default amount for counterIncOpThe
amount
parameter incounterIncOp
could be undefined. Consider setting a default value to ensure predictable behavior.- const { objectId, amount } = opts ?? {}; + const { objectId, amount = 1 } = opts ?? {};src/plugins/liveobjects/liveobjectspool.ts (1)
89-90
: Address TODO comments about subscription callbacksThe TODO comments indicate missing functionality for invoking subscription callbacks when operations are applied.
Would you like me to help implement the subscription callback functionality or create a GitHub issue to track this task?
Also applies to: 111-112
src/plugins/liveobjects/livemap.ts (2)
232-238
: Enhance error message for invalid state dataThe error message could be more descriptive by including the actual invalid values.
Apply this diff to improve the error message:
throw new ErrorInfo( - `Invalid state data for MAP_SET op on objectId=${this.getObjectId()} on key=${op.key}`, + `Invalid state data for MAP_SET op on objectId=${this.getObjectId()} on key=${op.key}. Expected either 'value' or 'objectId' to be defined, got: ${JSON.stringify(op.data)}`, 50000, 500, );
243-247
: Consider adding debug logging for zero-value object creationWhen creating zero-value objects, it would be helpful to log this event for debugging purposes.
Apply this diff to add logging:
+ this._client.Logger.logAction( + this._client.logger, + this._client.Logger.LOG_MICRO, + 'LiveMap._applyMapSet()', + `Creating zero-value object for objectId=${op.data.objectId}`, + ); this._liveObjects.getPool().createZeroValueObjectIfNotExists(op.data.objectId);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (13)
- scripts/moduleReport.ts (2 hunks)
- src/common/lib/client/realtimechannel.ts (2 hunks)
- src/plugins/liveobjects/livecounter.ts (1 hunks)
- src/plugins/liveobjects/livemap.ts (4 hunks)
- src/plugins/liveobjects/liveobject.ts (3 hunks)
- src/plugins/liveobjects/liveobjects.ts (6 hunks)
- src/plugins/liveobjects/liveobjectspool.ts (3 hunks)
- src/plugins/liveobjects/objectid.ts (1 hunks)
- src/plugins/liveobjects/statemessage.ts (1 hunks)
- src/plugins/liveobjects/syncliveobjectsdatapool.ts (4 hunks)
- src/plugins/liveobjects/timeserial.ts (1 hunks)
- test/common/modules/live_objects_helper.js (6 hunks)
- test/realtime/live_objects.test.js (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- scripts/moduleReport.ts
- src/plugins/liveobjects/objectid.ts
- src/plugins/liveobjects/statemessage.ts
- src/plugins/liveobjects/syncliveobjectsdatapool.ts
🧰 Additional context used
📓 Learnings (3)
src/plugins/liveobjects/livecounter.ts (1)
Learnt from: VeskeR PR: ably/ably-js#1897 File: src/plugins/liveobjects/livecounter.ts:93-93 Timestamp: 2024-10-22T13:26:59.680Z Learning: In the `LiveCounter` class's `_applyCounterCreate` method, it's intentional to increment the counter's value using `+=` instead of initializing it with `=` because the counter may have a pre-existing non-zero value.
src/plugins/liveobjects/liveobjects.ts (2)
Learnt from: VeskeR PR: ably/ably-js#1897 File: src/plugins/liveobjects/liveobjects.ts:145-146 Timestamp: 2024-10-22T14:22:00.033Z Learning: When reviewing code in the ably/ably-js repository, the user prefers that TODO comments are ignored.
Learnt from: VeskeR PR: ably/ably-js#1897 File: src/plugins/liveobjects/liveobjects.ts:84-94 Timestamp: 2024-10-22T14:21:46.501Z Learning: Ignore TODO comments in code during code reviews.
test/realtime/live_objects.test.js (1)
Learnt from: VeskeR PR: ably/ably-js#1897 File: test/realtime/live_objects.test.js:125-127 Timestamp: 2024-10-22T16:20:01.724Z Learning: In the file `test/realtime/live_objects.test.js`, the field name `regionalTimeserial` is correct and should not be changed to `timeserial`.
🪛 Biome
test/common/modules/live_objects_helper.js
[error] 198-198: The assignment should not be in an expression.
The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.(lint/suspicious/noAssignInExpressions)
🔇 Additional comments (26)
src/plugins/liveobjects/liveobject.ts (2)
1-3
: LGTM: Import statements are properly structuredThe new imports are correctly typed and appropriately scoped for the functionality being added.
10-10
: LGTM: Protected client property is well-definedThe protection level is appropriate for inheritance-based design. Let's verify the BaseClient implementation to ensure it provides all necessary functionality.
✅ Verification successful
Based on the shell script results, I can now generate the final response:
Protected _client property is correctly implemented and used
The BaseClient implementation in
src/common/lib/client/baseclient.ts
provides all necessary functionality including:
- HTTP and authentication handling
- Plugin management
- Logging capabilities
- Error handling utilities
The property is appropriately used in derived classes (LiveCounter, LiveMap) for:
- Error creation via
_client.ErrorInfo
- Logging via
_client.Logger
- Utility functions via
_client.Utils
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify BaseClient implementation and usage # Expected: Find BaseClient definition and its key methods # Look for BaseClient class definition echo "Searching for BaseClient implementation..." ast-grep --pattern 'class BaseClient { $$$ }' # Look for other LiveObject implementations that might need the client echo "Checking LiveObject implementations that would use _client..." ast-grep --pattern 'class $_ extends LiveObject { $$$ }'Length of output: 37805
src/plugins/liveobjects/livecounter.ts (4)
2-17
: LGTM: Constructor changes enhance state management capabilitiesThe updated constructor properly initializes the LiveCounter with state tracking capabilities, which aligns with the PR objectives for supporting operations outside of STATE_SYNC sequence.
32-44
: LGTM: Clean state management implementationThe state management methods are well-implemented with proper encapsulation and internal visibility.
84-120
: LGTM: Well-documented helper methods with intentional design choicesThe helper methods are well-implemented with clear documentation explaining the logic. The use of
+=
in_applyCounterCreate
is intentional and correct, as it handles cases where the counter may have a pre-existing non-zero value.
46-78
: LGTM: Robust operation handling with proper error casesThe operation handling is well-implemented with appropriate error handling. Let's verify the error codes are consistent with other parts of the codebase.
✅ Verification successful
Error codes 50000/500 are consistently used across the codebase for internal errors
The error codes (50000, 500) are used consistently throughout the codebase for internal errors and invalid state scenarios, similar to the usage in LiveCounter. This includes invalid object IDs, unknown types, and invalid states across various components like TimeSerial, PushChannel, and Transport.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Verify consistency of error codes across the codebase rg "new.*ErrorInfo.*50000.*500" --type tsLength of output: 2664
test/common/modules/live_objects_helper.js (2)
Line range hint
34-80
: LGTM! Well-structured test state initializationThe method creates a comprehensive test state tree with various data types and relationships. The code is well-documented and follows a logical sequence of operations.
Line range hint
174-196
: LGTM! Well-implemented state request handlingThe method properly handles single operation requests with good error handling and response processing.
src/plugins/liveobjects/liveobjects.ts (3)
70-76
: LGTM! Method rename improves clarity.The rename from
handleStateSyncMessage
tohandleStateSyncMessages
better reflects that the method handles multiple messages, improving code clarity and consistency.
87-93
: LGTM! New method implements out-of-sync state message handling.The implementation correctly delegates state message handling to the pool when not in sync, fulfilling the PR objective.
187-189
: LGTM! Proper type checking for LiveCounter created flag.The implementation correctly handles the created flag specifically for LiveCounter instances with proper type checking.
src/plugins/liveobjects/liveobjectspool.ts (3)
2-2
: LGTM: Channel integration looks goodThe addition of the RealtimeChannel member and its initialization is well-implemented and necessary for channel-related operations.
Also applies to: 17-17, 22-22
133-166
: LGTM: Well-structured handler methodsThe handler methods are well-implemented with:
- Proper null checks using isNil
- Clear documentation of zero-value cases
- Good separation of concerns
128-128
: LGTM: Consistent use of static factory methodGood use of the LiveMap.zeroValue factory method, maintaining consistency with the pattern used throughout the class.
src/plugins/liveobjects/livemap.ts (4)
Line range hint
1-36
: LGTM! Type changes improve type safetyThe interface updates and new imports enhance type safety by using
Timeserial
instead of string and makingdata
optional for tombstoned entries.
53-60
: LGTM! Well-implemented zero value patternThe
zeroValue
static method provides a clean way to create empty LiveMap instances.
104-114
: LGTM! Proper handling of tombstoned entriesThe get method correctly handles tombstoned entries and safely accesses data.
62-88
:⚠️ Potential issueAdd null check for entry.data access
The method could throw if
entry.data
is undefined when accessingentry.data.objectId
.Apply this diff to add null safety:
Object.entries(entries ?? {}).forEach(([key, entry]) => { + if (!entry.data) { + return; + } let liveData: StateData; if (typeof entry.data.objectId !== 'undefined') {Also, consider clarifying the comment about "optional parameters" as it's not immediately clear what parameters are being referred to.
Likely invalid or redundant comment.
src/common/lib/client/realtimechannel.ts (2)
Line range hint
624-685
: Implementation looks good overall!The implementation correctly handles both STATE and STATE_SYNC messages, properly integrates with the LiveObjects plugin, and maintains consistency with the existing message processing patterns in the codebase.
635-649
: Consider enhancing error handling for state message processing.The current error handling logs the error but continues processing subsequent messages. Consider whether failed messages should affect the processing of the entire batch or if additional error recovery mechanisms are needed.
test/realtime/live_objects.test.js (5)
39-40
: LGTM: Improved helper initialization.The change to use explicit constructor instantiation with
new
improves code clarity.
56-97
: LGTM: Well-structured test for STATE message handling.The test case properly verifies that regular message subscriptions continue to work after processing STATE messages without the LiveObjects plugin.
Line range hint
268-307
: LGTM: Comprehensive STATE_SYNC sequence testing.The test properly verifies the handling of STATE_SYNC messages with cursor and state data. The use of
regionalTimeserial
is correct as per established conventions.
498-865
: LGTM: Well-structured test scenarios for MAP operations.The test scenarios thoroughly verify MAP operations (CREATE, SET, REMOVE) with both primitive values and object references.
Line range hint
952-966
: LGTM: Clear channel attachment test.The test properly verifies that channels can be attached with LiveObjects state modes.
src/plugins/liveobjects/timeserial.ts (1)
1-179
: Well-structured implementation ofTimeserial
functionalityThe code effectively defines the
Timeserial
interface and provides a robust implementation inDefaultTimeserial
. Methods for parsing and comparing timeserials are well-designed, and error handling is appropriately implemented throughout.
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.
LGTM
…`STATE_SYNC` messages This implements the proposal from one of the earlier PRs [1] [1] #1897 (comment)
This PR implements all the bits and pieces required for LiveObjects plugin to apply incoming STATE operation messages outside the STATE_SYNC sequence (during STATE_SYNC sequence we will need to implement buffering of ops, see DTP-955).
I recommend reviewing this PR by going through the commits, as I've tried to structure them in a way that makes it easier to understand the changes and they have some additional comments in them.
Resolves DTP-954, DTP-956
Summary by CodeRabbit
Release Notes
New Features
RealtimeChannel
, improving interaction with live objects.LiveCounter
andLiveMap
classes to manage state operations and error handling.Timeserial
interface andDefaultTimeserial
class for managing timeserials.LiveObjectsPool
.ObjectId
class for managing object identifiers.handleStateMessages
method in theLiveObjects
class for improved state message management.SyncLiveObjectsDataPool
.handleStateSyncMessages
for better synchronization handling.Bug Fixes
Documentation
Tests