-
Notifications
You must be signed in to change notification settings - Fork 23
fix: await until sub is established and perform them in parallel #650
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
Manual Deploy AvailableYou can trigger a manual deploy of this PR branch to testnet: Alternative: Comment
Comment updated automatically when the PR is synchronized. |
WalkthroughConverts per-account subscription setup to async: Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant ChainPubsubActor
participant RemoteClient as PubsubClient
participant SubTask as SpawnedListener
rect rgba(200,230,255,0.6)
Caller->>ChainPubsubActor: Subscribe(pubkey) request
ChainPubsubActor->>ChainPubsubActor: insert AccountSubscription into map
ChainPubsubActor->>RemoteClient: account_subscribe(config) (await)
alt subscribe fails
ChainPubsubActor-->>Caller: Err(AccountSubscriptionsTaskFailed)
ChainPubsubActor->>ChainPubsubActor: abort/cleanup
else subscribe succeeds
ChainPubsubActor-->>Caller: Ok(())
ChainPubsubActor->>SubTask: spawn(listener with update_stream + cancel token)
loop updates
RemoteClient-->>SubTask: Update
SubTask->>ChainPubsubActor: forward update
end
alt EOF / cancellation
SubTask->>ChainPubsubActor: signal connection issue / abort
end
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used🧠 Learnings (6)📓 Common learnings📚 Learning: 2025-11-07T14:20:31.457ZApplied to files:
📚 Learning: 2025-10-21T14:00:54.642ZApplied to files:
📚 Learning: 2025-11-19T09:34:37.890ZApplied to files:
📚 Learning: 2025-10-26T16:53:29.820ZApplied to files:
📚 Learning: 2025-11-20T08:57:07.189ZApplied to files:
🧬 Code graph analysis (2)magicblock-chainlink/src/submux/mod.rs (4)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (2)
⏰ 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)
🔇 Additional comments (11)
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: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs(7 hunks)magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs(2 hunks)magicblock-chainlink/src/remote_account_provider/errors.rs(1 hunks)magicblock-chainlink/src/remote_account_provider/mod.rs(1 hunks)magicblock-chainlink/src/submux/mod.rs(4 hunks)magicblock-chainlink/src/submux/subscription_task.rs(1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs:457-495
Timestamp: 2025-11-07T14:20:31.457Z
Learning: In magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs, the unsubscribe closure returned by PubSubConnection::account_subscribe(...) resolves to () (unit), not a Result. Downstream code should not attempt to inspect an unsubscribe result and can optionally wrap it in a timeout to guard against hangs.
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579
📚 Learning: 2025-11-07T14:20:31.457Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs:457-495
Timestamp: 2025-11-07T14:20:31.457Z
Learning: In magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs, the unsubscribe closure returned by PubSubConnection::account_subscribe(...) resolves to () (unit), not a Result. Downstream code should not attempt to inspect an unsubscribe result and can optionally wrap it in a timeout to guard against hangs.
Applied to files:
magicblock-chainlink/src/remote_account_provider/mod.rsmagicblock-chainlink/src/remote_account_provider/errors.rsmagicblock-chainlink/src/submux/mod.rsmagicblock-chainlink/src/submux/subscription_task.rsmagicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rsmagicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs
📚 Learning: 2025-11-19T09:34:37.890Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 621
File: test-integration/test-chainlink/tests/ix_remote_account_provider.rs:62-63
Timestamp: 2025-11-19T09:34:37.890Z
Learning: In test-integration/test-chainlink/tests/ix_remote_account_provider.rs and similar test files, the `_fwd_rx` receiver returned by `init_remote_account_provider()` is intentionally kept alive (but unused) to prevent "receiver dropped" errors on the sender side. The pattern `let (remote_account_provider, _fwd_rx) = init_remote_account_provider().await;` should NOT be changed to `let (remote_account_provider, _) = ...` because dropping the receiver would cause send() operations to fail.
Applied to files:
magicblock-chainlink/src/remote_account_provider/mod.rsmagicblock-chainlink/src/remote_account_provider/errors.rsmagicblock-chainlink/src/submux/subscription_task.rsmagicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rsmagicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs
📚 Learning: 2025-10-26T16:53:29.820Z
Learnt from: thlorenz
Repo: magicblock-labs/magicblock-validator PR: 587
File: magicblock-chainlink/src/remote_account_provider/mod.rs:134-0
Timestamp: 2025-10-26T16:53:29.820Z
Learning: In magicblock-chainlink/src/remote_account_provider/mod.rs, the `Endpoint::separate_pubsub_url_and_api_key()` method uses `split_once("?api-key=")` because the api-key parameter is always the only query parameter right after `?`. No additional query parameter parsing is needed for this use case.
Applied to files:
magicblock-chainlink/src/remote_account_provider/mod.rsmagicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs
📚 Learning: 2025-10-21T14:00:54.642Z
Learnt from: bmuddha
Repo: magicblock-labs/magicblock-validator PR: 578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579
Applied to files:
magicblock-chainlink/src/remote_account_provider/errors.rsmagicblock-chainlink/src/submux/mod.rsmagicblock-chainlink/src/submux/subscription_task.rsmagicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rsmagicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs
🧬 Code graph analysis (3)
magicblock-chainlink/src/submux/mod.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (6)
unsubscribe(123-126)unsubscribe(219-235)unsubscribe(402-410)shutdown(127-127)shutdown(185-187)shutdown(412-412)magicblock-chainlink/src/testing/chain_pubsub.rs (1)
unsubscribe(45-57)magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
shutdown(160-175)
magicblock-chainlink/src/submux/subscription_task.rs (2)
magicblock-chainlink/src/submux/mod.rs (2)
clients(220-223)new(153-164)magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (2)
new(46-54)new(311-322)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (3)
unsubscribe(123-126)unsubscribe(219-235)unsubscribe(402-410)magicblock-chainlink/src/remote_account_provider/mod.rs (1)
unsubscribe(797-832)magicblock-chainlink/src/testing/chain_pubsub.rs (1)
unsubscribe(45-57)
🪛 GitHub Actions: Run CI - Format
magicblock-chainlink/src/submux/mod.rs
[error] 1387-1387: Rust fmt check failed due to formatting changes detected by cargo fmt. Apply formatting with 'cargo +nightly fmt' to fix this file.
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs
[error] 548-548: Rust fmt check failed due to formatting changes detected by cargo fmt. Apply formatting with 'cargo +nightly fmt' to fix this file.
⏰ 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: Build Project
- GitHub Check: run_make_ci_test
🔇 Additional comments (12)
magicblock-chainlink/src/remote_account_provider/mod.rs (1)
346-352: Error variant rename is consistent with new subscription orchestrationUsing
RemoteAccountProviderError::AccountSubscriptionsTaskFailed("No endpoints provided".to_string())keeps the existing control flow while aligning with the new, more generic subscription-task error variant. No functional concerns here.magicblock-chainlink/src/remote_account_provider/errors.rs (1)
32-33: Renamed error variant/message matches broader usage
AccountSubscriptionsTaskFailedwith “Failed to manage subscriptions ({0})” better describes both orchestration failures (SubMux) and setup failures (e.g., no endpoints). Shape compatibility is preserved, so downstream handling remains intact.magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (2)
385-400: Mock subscribe error now uses unified subscription-task variantThe disconnected-path error in
ChainPubsubClientMock::subscribenow surfaces asAccountSubscriptionsTaskFailed("mock: subscribe while disconnected"), which matches the new unified subscription-task error variant and keeps tests’ intent intact.
444-458: Mock resubscribe failure wired to AccountSubscriptionsTaskFailed
fail_next_resubscriptionsnow triggersAccountSubscriptionsTaskFailed("mock: forced resubscribe failure"), which integrates cleanly withSubMuxClient::reconnect_client’s retry logic and keeps the failure mode explicit for tests.magicblock-chainlink/src/submux/mod.rs (3)
26-28: New subscription_task module and re-export are straightforwardRe‑exporting
AccountSubscriptionTaskfromsubscription_taskcleanly exposes the orchestration primitive to the rest of the module without altering existing public SubMuxClient APIs.
149-152: Generic impl header change is purely cosmeticSwitching to
impl<T> SubMuxClient<T> where T: ChainPubsubClient + ReconnectableClientkeeps the same trait bounds while improving readability; no behavioral impact.
583-605: SubMuxClient now delegates subscribe/unsubscribe/shutdown to AccountSubscriptionTask
subscribe,unsubscribe, andshutdownnow callAccountSubscriptionTask::{Subscribe,Unsubscribe,Shutdown}.process(self.clients.clone()), which:
- attempts the operation on all inner clients in parallel,
- returns once the first client succeeds,
- and bubbles up
AccountSubscriptionsTaskFailedonly if every client fails.This is aligned with the PR goal of parallelizing subscriptions while still ensuring all inner clients eventually execute the operation.
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (5)
282-288: LGTM - Improved error propagation on disconnect.The change from trace logging to warning and explicit error response ensures that subscription attempts on disconnected clients fail fast with clear error signaling. This properly implements the PR objective of propagating RPC failures to callers.
301-302: LGTM - Correctly awaits async subscription.The
.awaitcorrectly handles the now-asyncadd_subfunction, ensuring subscription establishment completes before processing the next message. This is central to the PR's fix.
343-343: LGTM - Core change enabling synchronous subscription.Converting
add_subtoasync fnis the key change that enables awaiting the RPC subscription before returning, directly addressing the PR's objective.
384-411: LGTM - Core fix ensures subscription confirmed before returning.The refactored flow correctly addresses the PR objectives:
- RPC
account_subscribeis awaited outsidetokio::spawnOk(())is sent only after RPC succeeds (Line 411)- Errors are propagated to the requester (Line 405)
This ensures callers receive confirmation only after the RPC subscription is established, preventing premature LRU cache updates mentioned in the PR description.
Note: Lines 398-403 treat any RPC subscription failure as a connection issue (via
abort_and_signal_connection_issue), aborting all active subscriptions. This is aggressive—pubkey-specific errors (e.g., invalid pubkey) would also trigger a full abort. Based on the PR description this appears intentional, but verify this behavior is desired.
413-463: LGTM - Update listener correctly handles cancellation and EOF.The spawned task properly:
- Listens for updates until cancelled or EOF
- Handles cancellation with cleanup (unsubscribe + map removal)
- Handles EOF by signaling connection issue and returning early (Lines 434-446)
The early return on EOF is correct—
abort_and_signal_connection_issuealready removes from the map and cancels tokens. Not callingunsubscribewhen the connection is dead avoids potential hangs. Based on learnings, the timeout wrapper at Lines 452-459 correctly guards against hanging on dead sockets.Based on learnings
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs
Outdated
Show resolved
Hide resolved
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs
Outdated
Show resolved
Hide resolved
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs
Outdated
Show resolved
Hide resolved
* master: feat: persist all accounts (#648)
bmuddha
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
|
@bmuddha pointed out a bottleneck that this PR introduces and it is tracked in this issue to be fixed in a subsequent PR. |
## Summary
Ensure RemoteAccountProvider::subscribe waits for successful
subscription and submux subscribes to
inner clients in parallel.
## Problem
When `RemoteAccountProvider::subscribe` was called, the code had two
critical issues:
1. **Premature response before RPC completion**: The `add_sub` function
was spawning the RPC subscription call asynchronously but responding to
the caller immediately after spawn, not after the subscription actually
succeeded.
2. **Sequential subscription to all clients**: The
`SubMuxClient::subscribe` method was subscribing to all clients
sequentially and only returning when all succeeded, rather than waiting
for just one client to succeed.
This meant that:
- The caller would get an `Ok()` response without verifying the
subscription actually worked
- If the subscription failed, the error would not be propagated back to
the caller
- The LRU cache would be updated before verifying the subscription
actually worked
- Subscription would fail if any single client was disconnected
## Root Causes
### Issue 1: Sequential subscription in SubMuxClient
Original code in `submux/mod.rs`:
```rust
async fn subscribe(&self, pubkey: Pubkey) -> RemoteAccountProviderResult<()> {
for client in &self.clients {
client.subscribe(pubkey).await? // Fails if ANY client fails
}
Ok(())
}
```
This required ALL clients to succeed, instead of waiting for the first
success.
### Issue 2: Response sent before RPC call in ChainPubsubActor
Original code in `chain_pubsub_actor.rs`:
```rust
fn add_sub(...) {
tokio::spawn(async move {
// Make RPC call here (async)
let (mut update_stream, unsubscribe) = match pubsub_connection
.account_subscribe(&pubkey, config.clone())
.await
{
Ok(res) => res,
Err(err) => return,
};
// Send response AFTER spawn
let _ = sub_response.send(Ok(()));
// Listen for updates
});
// Function returns before RPC call completes
}
```
The response was sent inside the spawned task, so the function returned
before the RPC call completed.
### Issue 3: Disconnected actor returning success
When the actor was disconnected, it would still return `Ok(())`:
```rust
if !is_connected.load(Ordering::SeqCst) {
send_ok(response, client_id); // Returns success despite being disconnected
return;
}
```
## Solution
### Change 1: Parallel subscription with first-success semantics
Created a new `AccountSubscriptionTask` enum and `process()` method in
`submux/subscription_task.rs` that:
- Spawns subscription tasks to all clients in parallel using
`FuturesUnordered`
- Returns `Ok()` as soon as ANY client succeeds
- Collects errors from all clients only if ALL fail
- Ignores errors from clients after the first success
```rust
pub enum AccountSubscriptionTask {
Subscribe(Pubkey),
Unsubscribe(Pubkey),
Shutdown,
}
impl AccountSubscriptionTask {
pub async fn process<T>(self, clients: Vec<Arc<T>>) -> RemoteAccountProviderResult<()> {
tokio::spawn(async move {
let mut futures = FuturesUnordered::new();
// Spawn all client subscriptions in parallel
for (i, client) in clients.iter().enumerate() {
futures.push(async move {
let result = match task {
Subscribe(pubkey) => client.subscribe(pubkey).await,
// ...
};
(i, result)
});
}
let mut tx = Some(tx);
while let Some((i, result)) = futures.next().await {
match result {
Ok(_) => {
// First success - send and drop tx
if let Some(tx) = tx.take() {
let _ = tx.send(Ok(()));
}
}
Err(e) => {
if tx.is_none() {
// Already succeeded once, ignore subsequent errors
warn!("Error from client {}: {:?}", i, e);
} else {
errors.push(format!("Client {}: {:?}", i, e));
}
}
}
}
});
}
}
```
Updated `SubMuxClient` to use this:
```rust
async fn subscribe(&self, pubkey: Pubkey) -> RemoteAccountProviderResult<()> {
AccountSubscriptionTask::Subscribe(pubkey)
.process(self.clients.clone())
.await
}
```
### Change 2: Make add_sub async and verify RPC before responding
Changed `add_sub` from synchronous function to async, and moved the RPC
call outside the spawned task:
```rust
async fn add_sub(...) {
// ... setup ...
let config = RpcAccountInfoConfig { /* ... */ };
// Perform the subscription BEFORE spawning
let (mut update_stream, unsubscribe) = match pubsub_connection
.account_subscribe(&pubkey, config.clone())
.await
{
Ok(res) => res,
Err(err) => {
error!("[client_id={client_id}] Failed to subscribe to account {pubkey} {err:?}");
Self::abort_and_signal_connection_issue(/* ... */);
// RPC failed - inform the requester
let _ = sub_response.send(Err(err.into()));
return;
}
};
// RPC succeeded - confirm to the requester BEFORE spawning
let _ = sub_response.send(Ok(()));
// NOW spawn the background task to listen for updates
tokio::spawn(async move {
// Listen for updates and relay them
loop {
tokio::select! {
_ = cancellation_token.cancelled() => break,
update = update_stream.next() => {
// Relay update
}
}
}
// Cleanup
});
}
```
Updated caller to await it:
```rust
Self::add_sub(...).await; // Now awaits completion of RPC call
```
### Change 3: Return error when subscribing while disconnected
Changed actor to return error instead of success:
```rust
if !is_connected.load(Ordering::SeqCst) {
warn!("[client_id={client_id}] Ignoring subscribe request for {pubkey} because disconnected");
let _ = response.send(Err(
RemoteAccountProviderError::AccountSubscriptionsTaskFailed(
format!("Client {client_id} disconnected"),
),
));
return;
}
```
### Change 4: Error type consistency
Renamed and clarified error type from `AccountSubscriptionsFailed` to
`AccountSubscriptionsTaskFailed` across all files for consistency.
## Subscription Flow (After Fix)
1. **Entry Point**: `RemoteAccountProvider::subscribe(pubkey)` is called
2. Calls `register_subscription(pubkey)` →
`SubMuxClient::subscribe(pubkey)`
3. `SubMuxClient` creates `AccountSubscriptionTask::Subscribe(pubkey)`
and calls `process()`
4. **Parallel Subscription**: `process()` spawns subscription tasks to
ALL clients in parallel using `FuturesUnordered`
5. **First Success Wins**: Returns `Ok()` as soon as ANY client succeeds
6. Each client sends `AccountSubscribe` message to its
`ChainPubsubActor` and awaits response
7. **Actor Validates Connection**: Checks `is_connected` flag - returns
error if disconnected
8. **RPC Call Happens Now** (in the actor, not spawned): Calls
`account_subscribe()` and awaits result
9. **On RPC Success**: Sends `Ok()` response back (response goes all the
way back to caller)
10. **On RPC Failure**: Sends `Err` response back (tries next client)
11. **After RPC Confirmed**: Spawns background task to listen for update
stream
12. **Completion**: Caller receives response only after RPC subscription
is actually established
## Result
After these fixes, `RemoteAccountProvider::subscribe` will:
- Wait until at least one client successfully establishes an RPC
subscription
- Return error if all clients fail (rather than succeeding without
confirming)
- Fail fast if a client is disconnected
- Properly propagate RPC errors back to the caller
## <!-- This is an auto-generated comment: release notes by
coderabbit.ai -->
## Summary by CodeRabbit
* **Bug Fixes**
* Immediate failure notification when subscription setup fails or a
client disconnects; EOF and cancellation now trigger proper cleanup and
error replies.
* **Refactor**
* Subscription setup now occurs before per-subscription listeners to
avoid races; lifecycle and cancellation flows made more robust.
* **New Features**
* Centralized subscription task to coordinate
subscribe/unsubscribe/shutdown across clients.
* **Other**
* Renamed and standardized subscription error variant and message for
clearer reporting.
<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
* master: feat: use latest svm version (#657) chore: update solana account (#660) fix: better transaction diagnostics & rent exemption check (#642) chore: add access-control-max-age header to cors (#654) fix(aperture): prevent racy getLatestBlockhash (#649) fix: await until sub is established and perform them in parallel (#650) feat: persist all accounts (#648)
Summary
Ensure RemoteAccountProvider::subscribe waits for successful subscription and submux subscribes to
inner clients in parallel.
Problem
When
RemoteAccountProvider::subscribewas called, the code had two critical issues:Premature response before RPC completion: The
add_subfunction was spawning the RPC subscription call asynchronously but responding to the caller immediately after spawn, not after the subscription actually succeeded.Sequential subscription to all clients: The
SubMuxClient::subscribemethod was subscribing to all clients sequentially and only returning when all succeeded, rather than waiting for just one client to succeed.This meant that:
Ok()response without verifying the subscription actually workedRoot Causes
Issue 1: Sequential subscription in SubMuxClient
Original code in
submux/mod.rs:This required ALL clients to succeed, instead of waiting for the first success.
Issue 2: Response sent before RPC call in ChainPubsubActor
Original code in
chain_pubsub_actor.rs:The response was sent inside the spawned task, so the function returned before the RPC call completed.
Issue 3: Disconnected actor returning success
When the actor was disconnected, it would still return
Ok(()):Solution
Change 1: Parallel subscription with first-success semantics
Created a new
AccountSubscriptionTaskenum andprocess()method insubmux/subscription_task.rsthat:FuturesUnorderedOk()as soon as ANY client succeedsUpdated
SubMuxClientto use this:Change 2: Make add_sub async and verify RPC before responding
Changed
add_subfrom synchronous function to async, and moved the RPC call outside the spawned task:Updated caller to await it:
Change 3: Return error when subscribing while disconnected
Changed actor to return error instead of success:
Change 4: Error type consistency
Renamed and clarified error type from
AccountSubscriptionsFailedtoAccountSubscriptionsTaskFailedacross all files for consistency.Subscription Flow (After Fix)
RemoteAccountProvider::subscribe(pubkey)is calledregister_subscription(pubkey)→SubMuxClient::subscribe(pubkey)SubMuxClientcreatesAccountSubscriptionTask::Subscribe(pubkey)and callsprocess()process()spawns subscription tasks to ALL clients in parallel usingFuturesUnorderedOk()as soon as ANY client succeedsAccountSubscribemessage to itsChainPubsubActorand awaits responseis_connectedflag - returns error if disconnectedaccount_subscribe()and awaits resultOk()response back (response goes all the way back to caller)Errresponse back (tries next client)Result
After these fixes,
RemoteAccountProvider::subscribewill:Summary by CodeRabbit
Bug Fixes
Refactor
New Features
Other
✏️ Tip: You can customize this high-level summary in your review settings.