Solana WebSocket等待响应时冻结问题及超时方案咨询
Solana交易确认函数冻结问题分析与超时实现方案
问题原因
- WebSocket连接异常:如果WS客户端与节点的连接意外中断(比如网络波动、节点重启),
sub.Recv()会一直阻塞,既没有错误信号也没有新消息推送。 - 交易未被链上确认:比如交易手续费过低被节点丢弃、区块打包失败,或者节点未正确推送确认事件,导致函数卡在
Recv()调用上无限等待。 - Commitment级别匹配问题:使用
CommitmentConfirmed时,若交易最终未达到该确认状态(比如链上分叉导致交易被回滚),也会触发无限等待。
超时机制实现方案
通过context结合select实现超时控制,避免sub.Recv()无限阻塞:
import ( "context" "fmt" "time" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" "github.com/gagliardetto/solana-go/tpu" "github.com/gagliardetto/solana-go/ws" ) func SendAndConfirmTx( tpuClient *tpu.TPUClient, wsClient *ws.Client, transaction *solana.Transaction, timeout time.Duration, // 允许调用方自定义超时时长,比如传30*time.Second ) (signature solana.Signature, err error) { sig, err := tpuClient.SendTransaction(transaction, 50) if err != nil { return sig, err } sub, err := wsClient.SignatureSubscribe( sig, rpc.CommitmentConfirmed, ) if err != nil { return sig, err } defer sub.Unsubscribe() // 创建带超时的上下文,超时后自动触发终止信号 ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() for { select { // 监听超时信号 case <-ctx.Done(): return sig, fmt.Errorf("transaction confirmation timed out after %v", timeout) // 正常处理订阅消息 default: got, err := sub.Recv() if err != nil { return sig, fmt.Errorf("failed to receive confirmation: %v", err) } if got.Value.Err != nil { return sig, fmt.Errorf("transaction confirmation failed: %v", got.Value.Err) } else { return sig, nil } } } }
关键改动说明
- 新增
timeout参数,让调用方可以根据业务场景设置合理的超时时间(比如30秒)。 - 用
context.WithTimeout创建超时上下文,超时后ctx.Done()通道会立即触发,终止等待逻辑。 - 通过
select同时监听超时信号和订阅消息,一旦超时就直接返回错误,彻底避免无限阻塞。
额外优化建议
- 可以添加重试逻辑:超时后重新发起订阅,但要注意不要重复发送交易。
- 备选方案:如果WS订阅不稳定,可以搭配RPC轮询交易状态作为 fallback,双重保障确认逻辑。
内容的提问来源于stack exchange,提问作者hen
相关产品推荐
相关产品推荐

