-
Notifications
You must be signed in to change notification settings - Fork 1
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
[CHA-RL3][ECO-5011] Room RELEASE with retry #53
base: tests/roomlifecycle-detach
Are you sure you want to change the base?
[CHA-RL3][ECO-5011] Room RELEASE with retry #53
Conversation
WalkthroughThe pull request introduces several enhancements across multiple classes related to messaging and room management in a chat application. Key changes include the addition of a Changes
Assessment against linked issues
Possibly related 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 (
|
RoomLifecycleManager release
Added impl. for the release method across all room features
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: 7
🧹 Outside diff range and nitpick comments (7)
chat-android/src/main/java/com/ably/chat/Occupancy.kt (1)
Line range hint
57-62
: Critical: Implement TODO methods before releaseThe class has unimplemented core functionality:
subscribe(listener: Occupancy.Listener)
get(): OccupancyEvent
These methods are essential for the occupancy feature to work. They should be implemented before this PR is merged, especially since this PR is part of the CHA-RL3 specifications implementation.
Would you like me to help implement these methods or create a GitHub issue to track this work?
Also applies to: 67-70
chat-android/src/main/java/com/ably/chat/Rooms.kt (1)
Line range hint
31-37
: Enhance documentation for thread safety and coroutine contextThe documentation should clarify thread safety guarantees and coroutine context implications.
Add these details to the release method documentation:
/** * Release the Room object if it exists. This method only releases the reference * to the Room object from the Rooms instance and detaches the room from Ably. It does not unsubscribe to any * events. * * After calling this function, the room object is no-longer usable. If you wish to get the room object again, * you must call {@link Rooms.get}. * + * This method is thread-safe and can be called concurrently with other room operations. + * Being a suspend function, it should be called from a coroutine context. * * @param roomId The ID of the room. */chat-android/src/main/java/com/ably/chat/Presence.kt (1)
171-173
: Document the lifecycle dependency with MessagesThe implementation is correct as it relies on the Messages object to handle channel cleanup. However, consider documenting this dependency in the class-level KDoc to make the lifecycle relationship explicit.
Add this documentation to the class:
internal class DefaultPresence( private val messages: Messages, ) : Presence, ContributesToRoomLifecycleImpl(), ResolvedContributor { + /** + * DefaultPresence shares its underlying channel with Messages and relies on it for cleanup. + * The release() operation is a no-op as channel cleanup is handled by Messages. + */chat-android/src/main/java/com/ably/chat/Room.kt (2)
108-112
: Enhance documentation for the release method.The suspend function declaration looks good and aligns well with other lifecycle methods. However, the documentation could be more comprehensive.
Consider expanding the documentation to clarify:
/** * Releases the room, underlying channels are removed from the core SDK to prevent leakage. + * + * @throws ErrorInfo if the room is already released or in an invalid state + * @throws CancellationException if the coroutine is cancelled while releasing + * + * Note: After release, the room instance becomes invalid and any subsequent operations + * will fail. This operation is irreversible. */
Line range hint
164-173
: Review feature initialization strategy.The TODO comment indicates that only messages feature should be initialized by default, but currently all features are initialized.
Consider implementing a builder pattern or feature flags:
- Initialize only the messages feature by default
- Add other features based on RoomOptions
- This would reduce resource usage and improve initialization time
Example approach:
private fun initializeFeatures() { val features = mutableListOf<RoomFeature>(messages) if (options.presenceEnabled) { features.add(presence) } if (options.typingEnabled) { features.add(typing) } // ... other features _lifecycleManager = RoomLifecycleManager(roomScope, _statusLifecycle, features, _logger) }chat-android/src/main/java/com/ably/chat/RoomLifecycleManager.kt (2)
654-661
: Add a retry limit or backoff strategy inreleaseChannels()
The
releaseChannels()
method retries indefinitely ifdoRelease()
keeps failing, which could lead to an infinite loop and potential resource exhaustion. Consider adding a maximum retry limit or implementing an exponential backoff strategy to handle persistent failures gracefully.Example implementation with a retry limit:
private suspend fun releaseChannels() { + val maxRetries = 5 + var retryCount = 0 var contributorsReleased = kotlin.runCatching { doRelease() } while (contributorsReleased.isFailure) { // Wait a short period and then try again delay(_retryDurationInMs) + retryCount++ + if (retryCount >= maxRetries) { + throw contributorsReleased.exceptionOrNull() ?: Exception("Failed to release channels after $maxRetries attempts") + } contributorsReleased = kotlin.runCatching { doRelease() } } }
664-691
: Handle exceptions fromdetachCoroutine()
to release all contributorsCurrently, if
detachCoroutine()
throws an exception for any contributor, the exception is rethrown immediately, and the release process stops. This prevents other contributors from being released. Modify the code to collect exceptions and attempt to detach all contributors before rethrowing, ensuring that all resources are properly released.Apply this diff to collect exceptions:
private suspend fun doRelease() = coroutineScope { + val exceptions = mutableListOf<Throwable>() _contributors.map { contributor: ResolvedContributor -> async { // Skip failed or detached channels if (contributor.channel.state == ChannelState.failed || contributor.channel.state == ChannelState.detached) { return@async } try { contributor.channel.detachCoroutine() } catch (ex: Throwable) { // Log error before collecting - // TODO - log error here before rethrowing - throw ex + _logger?.log("Error detaching ${contributor.contributor.featureName}: ${ex.message}") + exceptions.add(ex) } } }.awaitAll() + if (exceptions.isNotEmpty()) { + // Optionally, aggregate exceptions or throw the first one + throw exceptions.first() + } _contributors.forEach { it.contributor.release() } _releaseInProgress = false _statusLifecycle.setStatus(RoomStatus.Released) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (9)
chat-android/src/main/java/com/ably/chat/Messages.kt
(2 hunks)chat-android/src/main/java/com/ably/chat/Occupancy.kt
(1 hunks)chat-android/src/main/java/com/ably/chat/Presence.kt
(1 hunks)chat-android/src/main/java/com/ably/chat/Room.kt
(2 hunks)chat-android/src/main/java/com/ably/chat/RoomLifecycleManager.kt
(3 hunks)chat-android/src/main/java/com/ably/chat/RoomReactions.kt
(2 hunks)chat-android/src/main/java/com/ably/chat/Rooms.kt
(1 hunks)chat-android/src/main/java/com/ably/chat/Typing.kt
(1 hunks)chat-android/src/main/java/com/ably/chat/Utils.kt
(1 hunks)
🔇 Additional comments (12)
chat-android/src/main/java/com/ably/chat/Occupancy.kt (2)
Line range hint 71-77
: LGTM: Well-structured error handling
The error handling is well-designed with specific error codes for attachment and detachment failures, properly integrating with the room lifecycle management.
84-86
: Verify the design decision for empty release()
The implementation comment suggests this method intentionally does nothing since it shares a channel with messages. Let's verify this design decision.
✅ Verification successful
The shell script results provide clear evidence about the release patterns across the codebase. Let me generate the final response:
Empty release() implementation is correct and consistent with codebase patterns
The empty implementation with the comment "No need to do anything, since it uses same channel as messages" is verified to be correct because:
Messages.kt
handles the actual channel release viarealtimeChannels.release(channel.name)
Presence.kt
follows the same pattern with an identical empty implementation and comment- Other components like
RoomReactions.kt
andTyping.kt
have their own channel management and thus implement channel release
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the channel sharing implementation and release handling in other components
# Check how other components handle channel release
echo "Checking channel release patterns across codebase:"
rg -A 5 "override fun release\(\)"
# Verify if Messages class is responsible for channel cleanup
echo "Checking Messages implementation:"
ast-grep --pattern 'class DefaultMessages {
$$$
override fun release() {
$$$
}
$$$
}'
Length of output: 2004
chat-android/src/main/java/com/ably/chat/Rooms.kt (1)
75-76
:
Thread safety concerns in release() method
The removal of synchronization in release()
while get()
remains synchronized could lead to race conditions. Consider these scenarios:
- Thread A calls
get()
while Thread B is executingrelease()
- Thread A and B both call
release()
simultaneously
Apply this diff to restore thread safety:
override suspend fun release(roomId: String) {
+ synchronized(this) {
val room = roomIdToRoom.remove(roomId)
room?.release()
+ }
}
Let's verify the thread safety requirements by checking for other synchronized operations in the codebase:
chat-android/src/main/java/com/ably/chat/Typing.kt (1)
Line range hint 74-89
: Verify the impact of unimplemented methods on release
The presence of multiple unimplemented methods (TODO) raises concerns about the completeness of the typing feature. We should verify if these methods need to be implemented before the release functionality can work correctly.
Let's check for any dependencies on these methods:
chat-android/src/main/java/com/ably/chat/Utils.kt (1)
60-65
: LGTM! The error message handling is consistent and well-implemented.
The new extension property follows the established pattern from Channel.errorMessage
and properly handles null safety. This addition enhances error reporting capabilities for room status changes, which aligns well with the PR's objectives for improving room management.
Let's verify the consistency of error message handling across the codebase:
✅ Verification successful
The error message handling is consistent with existing patterns
The implementation of RoomStatusChange.errorMessage
follows the same pattern as Channel.errorMessage
in the same file, both handling nullable error properties (error
and reason
respectively) in a consistent way. The RoomStatusChange
class correctly defines the error
property as ErrorInfo?
, making this extension property implementation appropriate and well-aligned with the codebase's error handling patterns.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for similar error message handling patterns
# and verify that RoomStatusChange has an error property
# Check for similar error message patterns
rg -U "val \w+\.errorMessage:.*\{.*error.*\}"
# Verify RoomStatusChange class structure
ast-grep --pattern 'class RoomStatusChange {
$$$
error: $_
$$$
}'
Length of output: 121
Script:
#!/bin/bash
# Let's try a broader search for error message patterns and RoomStatusChange
# Search for error message patterns with more flexible matching
rg -U "errorMessage.*error" -A 2 -B 2
# Search for RoomStatusChange class definition and usage
rg -U "class RoomStatusChange" -A 10 -B 2
# Search for files containing RoomStatusChange to understand its structure
fd -e kt -e java | xargs rg "RoomStatusChange"
Length of output: 2279
Script:
#!/bin/bash
# Let's check the RoomStatus.kt file to understand the error property
cat chat-android/src/main/java/com/ably/chat/RoomStatus.kt
# Let's also check for any similar error message handling patterns in Utils.kt
cat chat-android/src/main/java/com/ably/chat/Utils.kt
Length of output: 9554
chat-android/src/main/java/com/ably/chat/Presence.kt (1)
171-173
: Verify cleanup handling in Messages class
Since this implementation relies on Messages for cleanup, we should verify that Messages properly handles the channel cleanup.
✅ Verification successful
Let me gather more information about the Messages class implementation to verify the cleanup handling.
Let me search for the Room class implementation to understand the complete cleanup flow.
Let me try a different approach to search for the cleanup implementation.
Based on the gathered information, I can now provide the final response:
Channel cleanup is properly handled
The Messages class properly handles channel cleanup in its release method by calling realtimeChannels.release(channel.name)
. The Presence implementation correctly relies on the Messages channel cleanup since:
- Both Presence and Messages use the same underlying channel
- The Room's detach method explicitly calls
detachCoroutine()
on all channels - The Room's release method properly cascades to the lifecycle manager
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify that Messages handles channel cleanup in its release method
# Search for release method implementation in Messages-related files
echo "Searching for Messages release implementation..."
fd -e kt -e java . | xargs rg -A 10 "class.*Messages.*\{" | rg -A 10 "release.*\{"
# Search for channel cleanup patterns
echo "Searching for channel cleanup patterns..."
fd -e kt -e java . | xargs rg "channel\.(detach|dispose|close)"
Length of output: 871
Script:
#!/bin/bash
# Search for Messages class implementation
echo "Searching for Messages class implementation..."
ast-grep --pattern 'class Messages {
$$$
}'
# Search for channel initialization in Messages
echo "Searching for channel initialization in Messages..."
fd -e kt -e java . | xargs rg -B 5 -A 5 "class.*Messages" | rg -A 10 "channel.*="
# Search for detachCoroutine implementation
echo "Searching for detachCoroutine implementation..."
fd -e kt -e java . | xargs rg -A 5 "detachCoroutine"
Length of output: 9210
Script:
#!/bin/bash
# Search for Room class implementation
echo "Searching for Room class implementation..."
ast-grep --pattern 'class Room {
$$$
}'
# Search for RoomLifecycleManager release implementation
echo "Searching for RoomLifecycleManager release..."
fd -e kt -e java . | xargs rg -B 5 -A 10 "class.*RoomLifecycleManager" | rg -A 10 "release.*\{"
Length of output: 337
Script:
#!/bin/bash
# Search for release method implementations
echo "Searching for release methods..."
fd -e kt -e java . | xargs rg -B 5 -A 10 "override.*fun.*release"
# Search for channel cleanup in Room.kt
echo "Searching for channel cleanup in Room.kt..."
rg -B 10 -A 10 "detachCoroutine" chat-android/src/main/java/com/ably/chat/Room.kt
Length of output: 6222
chat-android/src/main/java/com/ably/chat/Room.kt (1)
207-208
: Verify cleanup of all room features.
Need to ensure proper cleanup of all room features (messages, presence, typing, reactions, occupancy).
✅ Verification successful
Let me gather more information about the actual cleanup implementation in the lifecycle manager and feature classes.
Room cleanup is properly implemented across all features
The verification shows that cleanup is correctly handled:
- RoomLifecycleManager properly coordinates release of all contributors
- Each feature implements appropriate cleanup:
- Messages: Releases its channel
- Typing: Releases its channel
- Reactions: Releases its channel
- Presence: No separate cleanup needed (shares Messages channel)
- Occupancy: No separate cleanup needed (shares Messages channel)
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for release implementations in feature classes
echo "Searching for release implementations in feature classes..."
rg -l "class Default(Messages|Presence|Typing|RoomReactions|Occupancy)" | xargs rg "fun release"
# Search for channel cleanup in lifecycle manager
echo "Searching for channel cleanup in lifecycle manager..."
rg -l "class RoomLifecycleManager" | xargs rg "fun release" -A 10
Length of output: 2209
Script:
#!/bin/bash
# Check the actual cleanup implementation in lifecycle manager
echo "Checking cleanup implementation in lifecycle manager..."
rg -l "class RoomLifecycleManager" | xargs rg "doRelease" -A 10
# Check cleanup implementations in feature classes
echo "Checking cleanup in Messages..."
rg -l "class DefaultMessages" | xargs rg "release" -A 5
echo "Checking cleanup in Presence..."
rg -l "class DefaultPresence" | xargs rg "release" -A 5
echo "Checking cleanup in Typing..."
rg -l "class DefaultTyping" | xargs rg "release" -A 5
echo "Checking cleanup in Reactions..."
rg -l "class DefaultRoomReactions" | xargs rg "release" -A 5
echo "Checking cleanup in Occupancy..."
rg -l "class DefaultOccupancy" | xargs rg "release" -A 5
Length of output: 2364
chat-android/src/main/java/com/ably/chat/RoomReactions.kt (3)
109-109
: LGTM: Well-structured dependency injection
The addition of realtimeChannels
parameter follows good practices by:
- Using dependency injection for better testability
- Maintaining proper encapsulation with private visibility
112-113
: LGTM: Clear and consistent feature name declaration
The explicit declaration of featureName
provides clear identification of this feature component.
166-168
: Add error handling and documentation to the release method
While the implementation is straightforward, consider these improvements:
- Add KDoc documentation explaining the purpose and behavior of the release operation
- Consider adding error handling for potential failures during channel release
Here's a suggested implementation:
+ /**
+ * Releases the reactions channel from the realtime channels.
+ * This should be called when the room is being cleaned up to prevent resource leaks.
+ *
+ * @throws AblyException if the channel release fails
+ */
override fun release() {
+ try {
realtimeChannels.release(channel.name)
+ } catch (e: AblyException) {
+ throw AblyException.fromErrorInfo(
+ ErrorInfo("Failed to release reactions channel: ${e.message}",
+ ErrorCodes.ReactionsDetachmentFailed.errorCode)
+ )
+ }
}
Let's verify if similar release methods in other components have error handling:
chat-android/src/main/java/com/ably/chat/Messages.kt (2)
226-226
: LGTM: Appropriate encapsulation of realtimeChannels
The visibility modification to private improves encapsulation while maintaining the required functionality.
230-231
: Verify consistent feature naming across components
The featureName "messages" is appropriate for this component.
✅ Verification successful
Feature naming is consistent across all components
The verification confirms that feature names are consistently used across all components:
- "typing" in Typing.kt
- "reactions" in RoomReactions.kt
- "presence" in Presence.kt
- "messages" in Messages.kt
- "occupancy" in Occupancy.kt
Each component has a unique and descriptive feature name that clearly identifies its responsibility.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for consistent feature naming across components
rg -g '*.kt' 'override val featureName' -A 1
Length of output: 827
val room = roomIdToRoom.remove(roomId) | ||
room?.release() |
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.
🛠️ Refactor suggestion
Improve error handling in release method
The current implementation silently handles errors from room.release()
. Consider propagating errors for better debugging and monitoring in production.
Apply this diff to improve error handling:
override suspend fun release(roomId: String) {
synchronized(this) {
val room = roomIdToRoom.remove(roomId)
- room?.release()
+ try {
+ room?.release()
+ } catch (e: Exception) {
+ clientOptions.logHandler.error("Failed to release room $roomId", e)
+ throw AblyException.fromErrorInfo(
+ ErrorInfo("Failed to release room: ${e.message}",
+ HttpStatusCodes.InternalServerError,
+ ErrorCodes.InternalError.errorCode,
+ e
+ )
+ )
+ }
}
}
Committable suggestion skipped: line range outside the PR's diff.
override fun release() { | ||
realtimeClient.channels.release(channel.name) | ||
} |
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.
🛠️ Refactor suggestion
Consider enhancing the release implementation
While the basic implementation is correct, consider these improvements:
- Add the
release()
method to theTyping
interface to make it part of the contract - Add error handling for potential channel release failures
- Add KDoc documentation explaining the purpose and behavior
Here's the suggested implementation:
interface Typing : EmitsDiscontinuities {
// ... existing methods ...
+ /**
+ * Releases resources associated with typing indicators.
+ * This includes releasing the underlying Ably channel.
+ */
+ suspend fun release()
}
internal class DefaultTyping(
// ... existing code ...
- override fun release() {
- realtimeClient.channels.release(channel.name)
- }
+ override suspend fun release() {
+ try {
+ realtimeClient.channels.release(channel.name)
+ } catch (e: Exception) {
+ throw ErrorInfo(
+ "Failed to release typing indicators channel",
+ ErrorCodes.TypingReleaseFailed,
+ cause = e
+ )
+ }
+ }
}
Committable suggestion skipped: line range outside the PR's diff.
override suspend fun release() { | ||
_lifecycleManager?.release() |
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.
Add null safety and state validation.
The current implementation has potential issues with null safety and lacks state validation.
Consider implementing proper null checks and state validation:
override suspend fun release() {
+ val lifecycleManager = _lifecycleManager ?: throw ErrorInfo(
+ "Room not properly initialized",
+ 40000
+ )
+
+ if (status == RoomStatus.Released) {
+ throw ErrorInfo("Room already released", 40001)
+ }
+
- _lifecycleManager?.release()
+ lifecycleManager.release()
}
Committable suggestion skipped: line range outside the PR's diff.
override fun release() { | ||
realtimeChannels.release(channel.name) | ||
} |
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.
🛠️ Refactor suggestion
Consider enhancing release() implementation robustness
While the implementation correctly releases the channel, consider these improvements for better resource cleanup:
- Add error handling for the release operation
- Clean up existing listeners and state
- Consider making the operation idempotent
Here's a suggested implementation:
override fun release() {
+ synchronized(lock) {
+ try {
+ realtimeChannels.release(channel.name)
+ listeners.clear()
+ channel.off(channelStateListener)
+ } catch (e: AblyException) {
+ // Log error but don't rethrow as we want to ensure cleanup continues
+ // logger.error("Error during channel release", e)
+ }
+ }
}
Committable suggestion skipped: line range outside the PR's diff.
|
||
/** | ||
* Underlying Realtime feature channel is removed from the core SDK to prevent leakage. | ||
*/ | ||
fun release() |
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.
Clarify documentation and provide default implementation for release()
Adding the release()
method to the ContributesToRoomLifecycle
interface may impact existing implementations since all subclasses must now implement this method. To prevent breaking changes, consider providing a default implementation in the interface. Additionally, the documentation for release()
could be clearer. Suggest rephrasing it to better describe the method's purpose.
Apply this diff to improve the documentation and provide a default implementation:
/**
- * Underlying Realtime feature channel is removed from the core SDK to prevent leakage.
+ * Releases resources held by the underlying Realtime feature channel to prevent resource leakage.
*/
-fun release()
+fun release() {
+ // Default implementation (if applicable)
+}
Committable suggestion skipped: line range outside the PR's diff.
/** | ||
* Are we in the process of releasing the room? | ||
*/ | ||
private var _releaseInProgress = false | ||
|
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.
Ensure thread safety of _releaseInProgress
The _releaseInProgress
flag may be accessed concurrently by multiple coroutines, leading to potential race conditions. To prevent this, consider using an AtomicBoolean
or other thread-safe mechanisms to manage this state.
Apply this diff to use an AtomicBoolean
:
+import java.util.concurrent.atomic.AtomicBoolean
/**
* Indicates whether a release operation is currently in progress.
*/
-private var _releaseInProgress = false
+private val _releaseInProgress = AtomicBoolean(false)
And update usages accordingly:
- if (_releaseInProgress) {
+ if (_releaseInProgress.get()) {
- _releaseInProgress = true
+ _releaseInProgress.set(true)
- _releaseInProgress = false
+ _releaseInProgress.set(false)
Committable suggestion skipped: line range outside the PR's diff.
val deferredRelease = atomicCoroutineScope.async(LifecycleOperationPrecedence.Release.priority) { // CHA-RL2i | ||
// If we're already released, this is a no-op | ||
if (_statusLifecycle.status === RoomStatus.Released) { | ||
return@async | ||
} | ||
|
||
// If we're already detached, then we can transition to released immediately | ||
if (_statusLifecycle.status === RoomStatus.Detached || | ||
_statusLifecycle.status === RoomStatus.Initialized | ||
) { | ||
_statusLifecycle.setStatus(RoomStatus.Released) | ||
return@async | ||
} | ||
|
||
// If we're in the process of releasing, we should wait for it to complete | ||
if (_releaseInProgress) { | ||
return@async listenToRoomRelease() | ||
} | ||
|
||
// We force the room status to be releasing | ||
clearAllTransientDetachTimeouts() | ||
_operationInProgress = true | ||
_releaseInProgress = true | ||
_statusLifecycle.setStatus(RoomStatus.Releasing) | ||
|
||
// Do the release until it completes | ||
return@async releaseChannels() | ||
} | ||
deferredRelease.await() | ||
} |
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.
Reset _releaseInProgress
in case of exceptions
In the release()
method, if releaseChannels()
throws an exception, _releaseInProgress
remains true
, potentially causing future release attempts to hang or behave incorrectly. To ensure proper resetting of the flag, update the code to reset _releaseInProgress
in a finally
block.
Apply this diff to adjust the code:
internal suspend fun release() {
val deferredRelease = atomicCoroutineScope.async(LifecycleOperationPrecedence.Release.priority) { // CHA-RL2i
// Existing checks...
// We force the room status to be releasing
clearAllTransientDetachTimeouts()
_operationInProgress = true
_releaseInProgress = true
_statusLifecycle.setStatus(RoomStatus.Releasing)
+ try {
// Do the release until it completes
return@async releaseChannels()
+ } finally {
+ _releaseInProgress = false
+ }
}
deferredRelease.await()
}
📝 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.
val deferredRelease = atomicCoroutineScope.async(LifecycleOperationPrecedence.Release.priority) { // CHA-RL2i | |
// If we're already released, this is a no-op | |
if (_statusLifecycle.status === RoomStatus.Released) { | |
return@async | |
} | |
// If we're already detached, then we can transition to released immediately | |
if (_statusLifecycle.status === RoomStatus.Detached || | |
_statusLifecycle.status === RoomStatus.Initialized | |
) { | |
_statusLifecycle.setStatus(RoomStatus.Released) | |
return@async | |
} | |
// If we're in the process of releasing, we should wait for it to complete | |
if (_releaseInProgress) { | |
return@async listenToRoomRelease() | |
} | |
// We force the room status to be releasing | |
clearAllTransientDetachTimeouts() | |
_operationInProgress = true | |
_releaseInProgress = true | |
_statusLifecycle.setStatus(RoomStatus.Releasing) | |
// Do the release until it completes | |
return@async releaseChannels() | |
} | |
deferredRelease.await() | |
} | |
val deferredRelease = atomicCoroutineScope.async(LifecycleOperationPrecedence.Release.priority) { // CHA-RL2i | |
// If we're already released, this is a no-op | |
if (_statusLifecycle.status === RoomStatus.Released) { | |
return@async | |
} | |
// If we're already detached, then we can transition to released immediately | |
if (_statusLifecycle.status === RoomStatus.Detached || | |
_statusLifecycle.status === RoomStatus.Initialized | |
) { | |
_statusLifecycle.setStatus(RoomStatus.Released) | |
return@async | |
} | |
// If we're in the process of releasing, we should wait for it to complete | |
if (_releaseInProgress) { | |
return@async listenToRoomRelease() | |
} | |
// We force the room status to be releasing | |
clearAllTransientDetachTimeouts() | |
_operationInProgress = true | |
_releaseInProgress = true | |
_statusLifecycle.setStatus(RoomStatus.Releasing) | |
try { | |
// Do the release until it completes | |
return@async releaseChannels() | |
} finally { | |
_releaseInProgress = false | |
} | |
} | |
deferredRelease.await() |
Fixed #23
Summary by CodeRabbit
New Features
release()
methods across various classes for improved resource management.errorMessage
extension property for enhanced error handling inRoomStatusChange
.Bug Fixes
Refactor
release()
method in theDefaultRooms
class by removing unnecessary synchronization.Documentation