-
Notifications
You must be signed in to change notification settings - Fork 97
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
Add configurable retry mechanism to broadcast interface #901
Conversation
This commit introduces error handling for network failures by implementing a retry mechanism. The broadcasting operation will now attempt to resend the message up to a defined maximum number of retries with a defined retry interval when a network error occurs, ensuring resilience against temporary connectivity issues.
WalkthroughThe changes introduce a new constant, Changes
Assessment against linked issues
Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
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 are a few important topics that need further discussion: 1. Individual Retries vs. Queue-based Retry Mechanism: However, @sejongk proposed an alternative approach: instead of retrying each request individually, why not queue up failed requests and process them once the network is reconnected? Since these events need to be sent anyway once the network is available, a queue-based retry mechanism could potentially be more efficient. Also, we could keep the interface simple as Liveblocks.
In this approach, we might need a separate loop similar to current
It might also be a good idea to apply
2. Broadcast Dependency Issue: |
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 (5)
packages/sdk/src/document/document.ts (3)
87-97
: Approved: New BroadcastOptions interface looks good.The new
BroadcastOptions
interface aligns well with the PR objectives, providing configurable retry mechanisms for handling network failures. The optionalerror
callback andmaxRetries
properties offer flexibility for users to customize error handling and retry behavior.Consider adding a
@see
tag in the JSDoc comment to link to related interfaces or methods, such as thebroadcast
method, for improved documentation navigation.
412-412
: Approved: LocalBroadcastEvent interface update is consistent.The addition of the optional
options
property of typeBroadcastOptions
to theLocalBroadcastEvent
interface is consistent with the changes made to theBroadcastEvent
interface. This update allows local broadcast events to include retry options, maintaining consistency across the broadcast-related interfaces.For improved consistency with the
BroadcastEvent
interface, consider adding a similar JSDoc comment to explain the purpose of theoptions
property in theLocalBroadcastEvent
interface.
2090-2097
: Approved: broadcast method update implements retry options.The
broadcast
method has been successfully updated to accept an optionaloptions
parameter of typeBroadcastOptions
. This change aligns with the PR objectives to introduce configurable retry mechanisms for handling network failures. The method correctly includes theoptions
in theLocalBroadcastEvent
, allowing the retry logic to be applied to broadcast operations.Consider the following improvements to enhance the method's robustness and usability:
- Add input validation for the
topic
andpayload
parameters to ensure they meet any required criteria (e.g., non-empty topic, valid JSON payload).- Implement error handling within the method to catch and process any exceptions that might occur during the broadcast operation.
- If there are default retry options, consider merging them with the provided options to ensure consistent behavior.
Example implementation:
public broadcast(topic: string, payload: Json, options?: BroadcastOptions) { if (!topic || typeof topic !== 'string') { throw new Error('Invalid topic: must be a non-empty string'); } // Merge with default options if necessary const mergedOptions = { ...DEFAULT_BROADCAST_OPTIONS, ...options }; try { const broadcastEvent: LocalBroadcastEvent = { type: DocEventType.LocalBroadcast, value: { topic, payload }, options: mergedOptions, }; this.publish([broadcastEvent]); } catch (error) { if (mergedOptions.error) { mergedOptions.error(error); } else { // Default error handling console.error('Broadcast failed:', error); } } }This implementation adds basic input validation, error handling, and merges the provided options with default options (if any).
packages/sdk/src/client/client.ts (2)
167-171
: Specify units in comments for clarity.To improve code readability, consider specifying the units (e.g., milliseconds) for
initialRetryInterval
andmaxBackoff
in the comments.
659-701
: Consider implementing a queue-based retry mechanism for broadcasts.As discussed in the PR comments, an alternative approach is to implement a queue-based retry mechanism. This could improve efficiency by managing retries globally and handling network reconnection events more effectively. It may also simplify the interface and provide better control over the order of broadcast events.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- packages/sdk/src/client/client.ts (5 hunks)
- packages/sdk/src/document/document.ts (6 hunks)
- packages/sdk/test/integration/client_test.ts (7 hunks)
🔇 Additional comments not posted (10)
packages/sdk/src/document/document.ts (1)
406-406
: Approved: BroadcastEvent interface update is consistent.The addition of the optional
options
property of typeBroadcastOptions
to theBroadcastEvent
interface is consistent with the PR objectives. This change allows for the inclusion of retry options in broadcast events, enhancing the flexibility of the broadcast functionality.packages/sdk/src/client/client.ts (3)
46-46
: Import ofJson
andBroadcastOptions
is appropriate.The necessary types are correctly imported from
'@yorkie-js-sdk/src/document/document'
.
319-322
: Event handler correctly handles optional options and error callback.The use of optional chaining ensures safe access to
event.options
and its properties without causing errors if they are undefined.
622-622
: Addition of optionaloptions
parameter tobroadcast
method is appropriate.This change maintains backward compatibility while allowing users to customize the broadcast behavior with retry options.
packages/sdk/test/integration/client_test.ts (6)
36-36
: Importing 'Json' enhances type safetyThe addition of
import { Json } from '@yorkie-js-sdk/src/document/document';
is appropriate since you're updatingEventCollector
instances to useJson
instead ofany
, improving type safety.
906-908
: Update 'broadcast' method call to use options object is correctThe
broadcast
method now correctly accepts an options object with anerror
handler. This change aligns with the updated method signature and enhances readability.
920-920
: Updating EventCollector to use 'Json' improves type safetyChanging the
EventCollector
type parameter fromany
toJson
ensures that the payload conforms to expected JSON structures, enhancing type safety.
951-951
: Updating EventCollector to use 'Json' improves type safetyChanging the
EventCollector
type parameter fromany
toJson
ensures that the payload conforms to expected JSON structures, enhancing type safety.
986-986
: Updating EventCollector to use 'Json' improves type safetyChanging the
EventCollector
type parameter fromany
toJson
ensures that the payload conforms to expected JSON structures, enhancing type safety.
1024-1025
: Updating EventCollectors to use 'Json' improves type safetyChanging
eventCollector1
andeventCollector2
type parameters fromany
toJson
ensures that the payloads conform to expected JSON structures, enhancing type safety.
7cd4c86
to
67db886
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
🧹 Outside diff range and nitpick comments (3)
packages/sdk/src/client/client.ts (3)
164-171
: LGTM! Consider making broadcast options configurable at the client level.The addition of
DefaultBroadcastOptions
is a good practice for providing default configuration values. However, to increase flexibility, consider making these options configurable at the client level. This would allow users to set their preferred default values for all broadcast operations when initializing the client.You could modify the
ClientOptions
interface to include these broadcast options:export interface ClientOptions { // ... existing options ... broadcastOptions?: { maxRetries?: number; initialRetryInterval?: number; maxBackoff?: number; }; }Then, in the Client constructor, you could merge these with the default options:
constructor(rpcAddr: string, opts?: ClientOptions) { // ... existing code ... this.broadcastOptions = { ...DefaultBroadcastOptions, ...opts?.broadcastOptions, }; // ... rest of the constructor }This approach would provide more flexibility while still maintaining sensible defaults.
Line range hint
619-701
: LGTM! Retry mechanism improves robustness, but there's a minor issue.The addition of a retry mechanism with exponential backoff is a great improvement to the
broadcast
method. It enhances the robustness of the system by handling transient network issues. The error handling distinguishing between retryable and non-retryable errors is also well implemented.However, there's a potential off-by-one error in the retry count increment:
The
retryCount
is incremented after scheduling the retry, which means the sameretryCount
is used for multiple retries. This affects the backoff timing calculation. To fix this, move the increment before scheduling the retry:if (retryCount < maxRetries) { + retryCount++; setTimeout(() => doLoop(), exponentialBackoff(retryCount - 1)); - retryCount++; logger.info( `[BC] c:"${this.getKey()}" retry attempt ${retryCount}/${maxRetries}`, );Also, consider optimizing the exponential backoff calculation by memoizing the
exponentialBackoff
function or pre-calculating the backoff times. This can be especially beneficial ifmaxRetries
is large:const backoffTimes = Array.from({ length: maxRetries }, (_, i) => Math.min(DefaultBroadcastOptions.initialRetryInterval * 2 ** i, maxBackoff) ); // Then in the retry logic: setTimeout(() => doLoop(), backoffTimes[retryCount - 1]);This optimization reduces repeated calculations of the backoff time.
46-46
: LGTM! Consider using object destructuring for cleaner default value assignment.The addition of the import statement for
Json
andBroadcastOptions
types is necessary and correct. The use of options with fallback to default values is also a good practice.To make the code slightly more concise and easier to read, consider using object destructuring with default values:
const { maxRetries = DefaultBroadcastOptions.maxRetries, maxBackoff = DefaultBroadcastOptions.maxBackoff } = options ?? {};This approach combines the retrieval of values from options and the assignment of default values in a single, clear statement.
Also applies to: 645-647
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- packages/sdk/src/client/client.ts (5 hunks)
- packages/sdk/src/document/document.ts (6 hunks)
- packages/sdk/test/integration/client_test.ts (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/sdk/src/document/document.ts
- packages/sdk/test/integration/client_test.ts
🔇 Additional comments not posted (1)
packages/sdk/src/client/client.ts (1)
Line range hint
1-1180
: Overall assessment: Significant improvements to broadcast functionality with minor optimization opportunities.The changes in this file greatly enhance the robustness of the broadcast functionality by introducing a retry mechanism with exponential backoff and improved error handling. The addition of
DefaultBroadcastOptions
and the option to customize these in thebroadcast
method provide good flexibility.Key improvements:
- Retry mechanism for handling transient network issues.
- Exponential backoff strategy to avoid overwhelming the server.
- Distinction between retryable and non-retryable errors.
Suggested optimizations:
- Fix the potential off-by-one error in retry count increment.
- Consider pre-calculating backoff times for performance.
- Make broadcast options configurable at the client level for greater flexibility.
- Use object destructuring for cleaner default value assignment.
These changes significantly improve the system's resilience to network issues while maintaining a clean and flexible API. The suggested optimizations, if implemented, would further enhance the code's efficiency and maintainability.
We've decided to to proceed with the current implementation (Individual Retries) for now. We can test it out and make improvements as we go. Additionally, I’ve removed the Lastly, I've set default |
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 👍
I hope to see many use cases of broadcasting of Yorkie! 😄 |
Implement a new BroadcastOptions interface to allow for automatic retries on network failures during broadcasts. This enhancement improves resilience against temporary network issues, ensuring more reliable message delivery. The maxRetries option allows users to control retry behavior, with a default of 0 (no retries). Only network errors trigger retries; other errors, such as unserializable payloads, will not initiate retry attempts.
What this PR does / why we need it?
This PR introduces a broadcast interface with configurable retry mechanisms. In the event of a network failure, the broadcast will automatically retry based on the provided settings.
Any background context you want to provide?
Here is the updated broadcast interface. The
BroadcastOptions
interface includes optional settings forerror
callbacks,maxRetries
. Retry options apply only to network errors. (retries will not occur for non-network errors such as broadcasting unserializable payloads.)I'm concerned that the
maxRetries
option is not as intuitive as theshouldQueueEventIfNotReady
option provided by Liveblocks.We could also provide the same option by two possible solutions:
The simplest approach would be to set
maxRetries
toInfinity
, though this may lead to performance issues.Another approach is to implement a loop similar to
runSyncLoop
for broadcasts, continuously checking if the network is restored. However, adding a separate loop for broadcasting feels redundant at this point. Therefore, I've opted to keep the solution as simple as possible for now.What are the relevant tickets?
Fixes #891
Checklist
Summary by CodeRabbit
Summary by CodeRabbit
New Features
DefaultBroadcastOptions
for enhanced broadcasting settings, including retry logic.Bug Fixes
Tests