Skip to content

fix: Enhance connection robustness by rebuilding NWConnection on failure - #71

Open
RainYangty wants to merge 1 commit into
MaaAssistantArknights:masterfrom
RainYangty:failed
Open

fix: Enhance connection robustness by rebuilding NWConnection on failure#71
RainYangty wants to merge 1 commit into
MaaAssistantArknights:masterfrom
RainYangty:failed

Conversation

@RainYangty

Copy link
Copy Markdown
Contributor

Summary

This Pull Request refactors the MaaToolClient initialization logic to significantly improve its resilience when establishing a network connection.

The original implementation attempted to handle the .failed connection state primarily by calling connection.restart(). While this works for the .waiting state, a hard .failed state in NWConnection often requires a more thorough reset.

The fix introduces an outer while loop around the connection setup. Now, when a connection enters the .failed state, the client explicitly calls connection.cancel() on the faulty instance, breaks out of the state-watching loop, and allows the outer while loop to create a completely new NWConnection for the next retry attempt.

This ensures a cleaner and more reliable retry mechanism, as it avoids depending on the internal state recovery of the previously failed connection object. The core functionality and connection properties remain the same.

Reason for Change

In networking, especially when dealing with explicit connection failures (e.g., connection refused, network down), simply calling restart() on an existing connection object that is in a .failed state may not always succeed, as the underlying resources might not be cleanly released.

The revised logic offers a more definitive reset for failed connection attempts:

  1. Old Logic: .failed $\rightarrow$ connection.restart() (Potentially unreliable).
  2. New Logic: .failed $\rightarrow$ connection.cancel() $\rightarrow$ Break Inner Loop $\rightarrow$ Create New NWConnection (More reliable, full reset).

Additionally, the PR includes minor refactoring to enhance concurrency safety within the actor:

  • The connection property is changed from let to var to allow for re-assignment within the initializer's retry loop.
  • A private helper method cancelActorConnection() is introduced to safely perform connection.cancel() within the actor's isolated context, particularly when the AsyncStream is terminated.

Key Changes

  1. Connection Property: Changed private let connection: NWConnection to private var connection: NWConnection.
  2. Retry Loop Refactor: Wrapped the connection creation and state monitoring in a while loop.
  3. Handling .failed State: In the state machine, case .failed now explicitly calls connection.cancel() and uses a labeled break (break state_enum) to exit the inner for await state loop, initiating the creation of a new connection by the outer while loop.
  4. Concurrency Safety: Added private func cancelActorConnection() and updated the AsyncStream.onTermination handler to call this method, ensuring connection.cancel() is performed safely on the actor.

Files Affected

  • MaaToolClient.swift


摘要

本次拉取请求(PR)重构了 MaaToolClient 的初始化逻辑,以显著提高其在建立网络连接时的健壮性。

原始实现主要通过调用 connection.restart() 来处理连接失败的 .failed 状态。虽然这对 .waiting 状态是有效的,但对于硬性的 .failed 状态,NWConnection 通常需要更彻底的重置。

此修复在连接设置的外部引入了一个 while 循环。现在,当连接进入 .failed 状态时,客户端会显式地对失败的实例调用 connection.cancel(),跳出状态监听循环,并允许外部 while 循环在下一次重试时创建一个全新的 NWConnection 实例

这确保了更清晰、更可靠的重试机制,因为它避免了依赖先前失败连接对象的内部状态恢复。核心功能和连接属性保持不变。

更改原因

在网络编程中,特别是在遇到明确的连接失败(例如:连接被拒绝、网络中断)时,简单地对处于 .failed 状态的现有连接对象调用 restart() 可能无法总是成功,因为底层资源可能没有被彻底释放。

修改后的逻辑为失败的连接尝试提供了更明确的重置

  1. 旧逻辑: .failed $\rightarrow$ connection.restart() (可能不可靠)。
  2. 新逻辑: .failed $\rightarrow$ connection.cancel() $\rightarrow$ 跳出内部循环 $\rightarrow$ 创建新的 NWConnection (更可靠,完全重置)。

此外,此 PR 还包含细微的重构,以增强 actor 内的并发安全性:

  • connection 属性从 let 更改为 var,以便在初始化程序的重试循环中能够重新赋值。
  • 引入了一个私有的辅助方法 cancelActorConnection(),用于安全地在 Actor 的隔离上下文中执行 connection.cancel(),特别是在 AsyncStream 终止时。

主要更改

  1. 连接属性:private let connection: NWConnection 更改为 private var connection: NWConnection
  2. 重试循环重构: 使用 while 循环包裹连接创建和状态监控逻辑。
  3. 处理 .failed 状态: 在状态机中,case .failed 现在显式调用 connection.cancel(),并使用带标签的 break (break state_enum) 跳出内部 for await state 循环,由外部 while 循环来启动新连接的创建。
  4. 并发安全: 新增 private func cancelActorConnection(),并更新 AsyncStream.onTermination 处理器以调用此方法,确保 connection.cancel() 在 Actor 上安全执行。

受影响的文件

  • MaaToolClient.swift

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant