-
Notifications
You must be signed in to change notification settings - Fork 41
fix: reconnect breaks async requests #1176
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
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds explicit reconnect support for async HTTP by introducing connect() methods that reinitialize the async thread pool after a prior close: AblyRealtime.connect() → AblyBase.connect() → Http.connect() → AsyncHttpScheduler.connect() → CloseableThreadPoolExecutor.connect(). Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant AblyRealtime
participant AblyBase
participant Http
participant AsyncHttpScheduler
participant CloseableThreadPoolExecutor
Client->>AblyRealtime: connect()
activate AblyRealtime
AblyRealtime->>AblyBase: super.connect()
activate AblyBase
AblyBase->>Http: connect()
activate Http
Http->>AsyncHttpScheduler: connect()
activate AsyncHttpScheduler
AsyncHttpScheduler->>CloseableThreadPoolExecutor: connect()
activate CloseableThreadPoolExecutor
Note over CloseableThreadPoolExecutor: Recreate thread pool if shutdown
CloseableThreadPoolExecutor-->>AsyncHttpScheduler: ready
deactivate CloseableThreadPoolExecutor
AsyncHttpScheduler-->>Http: ready
deactivate AsyncHttpScheduler
Http-->>AblyBase: ready
deactivate Http
AblyBase-->>AblyRealtime: ready
deactivate AblyBase
AblyRealtime->>AblyRealtime: connection.connect()
AblyRealtime-->>Client: connected
deactivate AblyRealtime
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
lib/src/main/java/io/ably/lib/http/AsyncHttpScheduler.java (1)
69-79: Consider synchronization to prevent race condition.The check-then-act pattern (line 70: check
isShutdown(), lines 71-77: create new executor) is not atomic. If multiple threads callconnect()simultaneously afterclose(), both could create new executors, with the second overwriting the first, leaking resources.While unlikely in the expected single-threaded usage (close → connect), adding
synchronizedwould eliminate the risk with minimal overhead.Consider this change:
- public void connect() { + public synchronized void connect() { if (executor.isShutdown()) { executor = new ThreadPoolExecutor(
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
lib/src/main/java/io/ably/lib/http/AsyncHttpScheduler.java(2 hunks)lib/src/main/java/io/ably/lib/http/Http.java(1 hunks)lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java(1 hunks)lib/src/main/java/io/ably/lib/rest/AblyBase.java(1 hunks)lib/src/test/java/io/ably/lib/test/realtime/RealtimeConnectTest.java(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
lib/src/test/java/io/ably/lib/test/realtime/RealtimeConnectTest.java (3)
lib/src/test/java/io/ably/lib/test/common/Helpers.java (1)
Helpers(74-1229)lib/src/main/java/io/ably/lib/types/AsyncHttpPaginatedResponse.java (1)
AsyncHttpPaginatedResponse(5-44)lib/src/main/java/io/ably/lib/types/ErrorInfo.java (1)
ErrorInfo(17-197)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: build
- GitHub Check: check
- GitHub Check: check-liveobjects
- GitHub Check: check-realtime-okhttp
- GitHub Check: check (29)
- GitHub Check: check-rest-okhttp
- GitHub Check: check (29)
- GitHub Check: check-rest
- GitHub Check: check-realtime
- GitHub Check: check (19)
- GitHub Check: check (24)
- GitHub Check: check (21)
🔇 Additional comments (5)
lib/src/main/java/io/ably/lib/http/Http.java (1)
24-26: LGTM! Clean delegation to async HTTP scheduler.The method correctly delegates to
asyncHttp.connect()to reinitialize the thread pool after close.lib/src/main/java/io/ably/lib/rest/AblyBase.java (1)
141-146: LGTM! Appropriate internal API for realtime client.The protected visibility and clear documentation make this a clean internal extension point for
AblyRealtime.lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (1)
99-102: LGTM! Correct sequencing for thread pool recovery.Calling
super.connect()beforeconnection.connect()ensures the async HTTP thread pool is restored before establishing the WebSocket connection. This addresses the core issue where async operations fail after reconnect.lib/src/main/java/io/ably/lib/http/AsyncHttpScheduler.java (2)
36-38: LGTM! Clean delegation pattern.
41-54: Good defensive design with volatile executor field.Making
executorvolatile ensures visibility across threads, and storingoptionsenables correct thread pool recreation. The comment at line 41 helpfully explains the rationale.
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.
Pull Request Overview
This PR fixes an issue where REST API requests fail after a realtime connection is reopened (closed then reconnected). The fix ensures the HTTP thread pool is properly reinitialized when connect() is called after a previous close().
Key changes:
- Added a
connect()method chain throughAblyRealtime→AblyBase→Http→AsyncHttpSchedulerto reinitialize the thread pool - Modified
CloseableThreadPoolExecutorto check if the executor is shutdown and create a new one if needed - Added test coverage for the reopened connection REST functionality scenario
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java | Overrides connect() to call parent method for HTTP thread pool reset |
| lib/src/main/java/io/ably/lib/rest/AblyBase.java | Adds protected connect() method to reinitialize HTTP layer |
| lib/src/main/java/io/ably/lib/http/Http.java | Delegates connect() call to async HTTP scheduler |
| lib/src/main/java/io/ably/lib/http/AsyncHttpScheduler.java | Implements thread pool reinitialization logic and removes deprecated finalize method |
| lib/src/test/java/io/ably/lib/test/realtime/RealtimeConnectTest.java | Adds test case verifying REST requests work after connection is reopened |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
lib/src/test/java/io/ably/lib/test/realtime/RealtimeConnectTest.java
Outdated
Show resolved
Hide resolved
Introduced `connect()` in `AblyBase` to reset thread pools when `AblyRealtime.connect()` is called after `close()`
764e71c to
6e8a5a6
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
♻️ Duplicate comments (1)
lib/src/main/java/io/ably/lib/http/AsyncHttpScheduler.java (1)
69-79: Consider guarding against multiple connect() calls and resource leaks.The method only recreates the executor if it's shutdown, which is correct. However:
Race condition (as noted in previous review): Between checking
isShutdown()on line 70 and creating the new executor on line 71, another thread could callexecute()on the shutdown executor, resulting in aRejectedExecutionException. While the developer noted this is the user's responsibility, consider documenting this threading requirement clearly.Idempotency consideration: If
connect()is called when the executor is NOT shutdown, nothing happens. This is likely intentional but should be documented. Alternatively, consider logging a warning ifconnect()is called on a non-shutdown executor to help users debug unexpected behavior.public void connect() { if (executor.isShutdown()) { executor = new ThreadPoolExecutor( options.asyncHttpThreadpoolSize, options.asyncHttpThreadpoolSize, KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>() ); + } else { + Log.w(TAG, "connect() called on non-shutdown executor; ignoring"); } }
🧹 Nitpick comments (2)
lib/src/main/java/io/ably/lib/rest/AblyBase.java (1)
141-146: Enhance documentation and consider idempotency.The JavaDoc comment should follow the standard format used by other methods in this class and explain:
- When this method should be called (e.g., after
close())- What it does (reinitializes the async thread pool)
- Whether it's safe to call multiple times
- The relationship to
close()and the connection lifecycleConsider adding a check to make this method idempotent—currently, calling
connect()multiple times could have unclear behavior depending on the underlyinghttp.connect()implementation.lib/src/main/java/io/ably/lib/http/AsyncHttpScheduler.java (1)
36-38: Add JavaDoc for the public connect() method.This method is part of the public API but lacks documentation. Add JavaDoc explaining:
- Its purpose (reinitializes the async thread pool after shutdown)
- When it should be called (after close() or when the executor has been shut down)
- Whether it's safe to call multiple times
- Any threading considerations
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
lib/src/main/java/io/ably/lib/http/AsyncHttpScheduler.java(2 hunks)lib/src/main/java/io/ably/lib/http/Http.java(1 hunks)lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java(1 hunks)lib/src/main/java/io/ably/lib/rest/AblyBase.java(1 hunks)lib/src/test/java/io/ably/lib/test/realtime/RealtimeConnectTest.java(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- lib/src/main/java/io/ably/lib/http/Http.java
- lib/src/test/java/io/ably/lib/test/realtime/RealtimeConnectTest.java
- lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: check-realtime-okhttp
- GitHub Check: check-realtime
🔇 Additional comments (1)
lib/src/main/java/io/ably/lib/http/AsyncHttpScheduler.java (1)
41-43: Volatile ensures visibility but not atomicity.Good use of
volatilefor theexecutorfield to ensure visibility of the reference across threads. However, note that this doesn't prevent race conditions betweenconnect()andexecute()or between multipleconnect()calls—it only ensures threads see the most recent reference.The addition of the
optionsfield enables recreating the executor with the correct configuration.
sacOO7
left a comment
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
Resolves #1175
Introduced
connect()inAblyBaseto reset thread pools whenAblyRealtime.connect()is called afterclose()Summary by CodeRabbit
New Features
Tests