IBMSwiftCircuitBreaker 5.0.3

IBMSwiftCircuitBreaker 5.0.3

Matt KilnerDavid JonesAndrew Lees 维护。



  • IBM

Kitura

APIDoc Build Status - Master macOS Linux Apache 2 Slack Status

CircuitBreaker

Circuit Breaker 设计模式用于提高应用稳定性,改善响应时间,并防止应用不断发出失败请求。此库提供了将 Circuit Breaker 逻辑引入 Swift 应用程序所需的工具。

Circuit Breaker Diagram

Swift 版本

CircuitBreaker 的最新版本与 Swift 二进制文件(版本 4.1.2 及更高版本)兼容。您可以通过以下链接下载此版本的 Swift 二进制文件:链接

入门指南

CircuitBreaker 添加到您应用程序 Package.swift 文件中的依赖项。将 "x.x.x" 替换为最新的 CircuitBreaker 发布版本

.package(url: "https://github.com/IBM-Swift/CircuitBreaker.git", from: "x.x.x")

CircuitBreaker 添加到您的目标的依赖项

.target(name: "example", dependencies: ["CircuitBreaker"]),

在您的应用程序内部导入该包

import CircuitBreaker

使用方法

CircuitBreaker 状态基于超时和用户定义的失败(当您要断路转换的函数进行异步调用时非常有用)。要在您的应用程序代码中使用 CircuitBreaker,您需要执行以下操作

  • 定义一个具有签名 (BreakerError, (fallbackArg1, fallbackArg2, ...)) -> Void 的回退函数
func myFallback(err: BreakerError, msg: String) {
    // The fallback will be called if one of the below occurs:
    //  1. The request does not return before the specified timeout
    //  2. CircuitBreaker is currently in Open state and set to fail fast.
    //  3. There was an error in the user's called context function (networking error, etc.)
    Log.verbose("Error: \(err)")
    Log.verbose("Message: \(msg)")
}
  • 通过定义您自己的错误处理来扩展 BreakerError 以在上下文函数中使用
extension BreakerError {
    public static let encodingURLError = BreakerError(reason: "URL could not be created")
    public static let networkingError = BreakerError(reason: "There was an error, while sending the request")
    public static let jsonDecodingError = BreakerError(reason: "Could not decode result into JSON")
}
  • 为你要执行熔断的逻辑创建一个上下文函数(这样你可以向熔断器报告失败或成功)。上下文函数接收一个Invocation对象作为其参数。一个Invocation类的实例表示以下内容
    • 必须传递给上下文函数的参数类型。
    • 上下文函数执行后的返回类型。
    • 用作后备闭包第二个参数的参数类型。
func myContextFunction(invocation: Invocation<(String), String>) {
  let requestParam = invocation.commandArgs
  // Create HTTP request
  guard let url = URL(string: "http://myserver.net/path/\(requestParam)") else {
    // Something went wrong

    invocation.notifyFailure(error: .encodingURLError)
    return
  }

  var req = URLRequest(url: url)
  req.httpMethod = "GET"
  let session = URLSession.shared

  // Perform the request
  session.dataTask(with: req) { result, res, err in
    guard let result = result else {
      // Failed getting a result from the server

      invocation.notifyFailure(error: .networkingError)
      return
    }

    // Convert results to a JSON object
    guard let json = (try? JSONSerialization.jsonObject(with: result, options: [])) as? [String: Any] else {
      invocation.notifyFailure(error: .jsonDecodingError)
      return
    }
    // Process JSON data

    invocation.notifySuccess()
  }.resume()
}
  • 为每个你想进行熔断的上下文函数(例如端点)创建一个CircuitBreaker实例。熔断器实例必须指定熔断器的名称、要熔断的端点和后备函数。可选的配置包括:group、timeout、resetTimeout、maxFailures、rollingWindow和bulkhead,有关这些配置选项的详细信息,请参见API参考
let breaker = CircuitBreaker(name: "Circuit1", command: myContextFunction, fallback: myFallback)
  • 通过调用CircuitBreaker的run()方法来调用端点的调用。你应该为上下文命令和后备闭包传递相应的参数。在此示例中,myContextFunction以字符串作为其参数,而myFallback以字符串作为第二个参数。
let requestParam: String = "myRequestParams"
breaker.run(commandArgs: requestParam, fallbackArgs: "Something went wrong.")

完整实现

extension BreakerError {
    public static let encodingURLError = BreakerError(reason: "URL could not be created")
    public static let networkingError = BreakerError(reason: "There was an error, while sending the request")
    public static let jsonDecodingError = BreakerError(reason: "Could not decode result into JSON")
}

func myFallback(err: BreakerError, msg: String) {
    // The fallback will be called if one of the below occurs:
    //  1. The request does not return before the specified timeout
    //  2. CircuitBreaker is currently in Open state and set to fail fast.
    //  3. There was an error in the user's called context function (networking error, etc.)
    Log.verbose("Error: \(err)")
    Log.verbose("Message: \(msg)")
}

func myContextFunction(invocation: Invocation<(String), String>) {
  let requestParam = invocation.commandArgs
  // Create HTTP request
  guard let url = URL(string: "http://mysever.net/path/\(requestParam)") else {
    // Something went wrong...

    invocation.notifyFailure(error: .encodingURLError)
  }

  var req = URLRequest(url: url)
  req.httpMethod = "GET"
  let session = URLSession.shared

  // Perform Request
  session.dataTask(with: req) { result, res, err in
    guard let result = result else {
      // Failed getting a result from the server

      invocation.notifyFailure(error: .networkingError)
      return
    }

    // Convert results to a JSON object
    guard let json = (try? JSONSerialization.jsonObject(with: result, options: [])) as? [String: Any] else {
        invocation.notifyFailure(error: .jsonDecodingError)
        return
    }
    // Process JSON data

    invocation.notifySuccess()
  }.resume()
}

let breaker = CircuitBreaker(name: "Circuit1", command: myContextFunction, fallback: myFallback)

let requestParam: String = "myRequestParams"
breaker.run(commandArgs: requestParam, fallbackArgs: "Something went wrong.")

统计数据

以下统计数据将被跟踪以记录熔断器实例

跟踪统计
  • 总请求数
  • 并发请求
  • 拒绝请求
  • 成功响应
  • 平均执行响应时间
  • 平均总响应时间
  • 失败响应
  • 总超时时间
  • 总延迟
  • 总执行延迟
  • Hystrix兼容快照

以下示例代码显示如何记录统计信息的快照以及如何创建Hystrix兼容的快照。

// Create CircuitBreaker
let breaker = CircuitBreaker(name: "Circuit1", command: myFunction, fallback: myFallback)

// Invoke breaker call
breaker.run(commandArgs: (a: 10, b: 20), fallbackArgs: "Something went wrong.")

// Log statistics snapshot
breaker.logSnapshot()

// Hystrix compliant snapshot
let snapshot = breaker.snapshot

观察数据统计

CircuitBreaker 库提供了一个用于观察新的 CircuitBreaker 实例的接口,以便注册和跟踪统计信息的变化。在 CircuitBreaker 实例的初始化过程中,连接的监控器会接到其实例化的通知,从而使它们开始跟踪该实例的统计信息。CircuitBreaker 实例向监控器公开了一个与 Hystrix 兼容的统计快照,监控器可以据此进行处理。有关更多信息,请参阅 API 文档。

API 文档

欲了解更多信息,请访问我们的 API 参考文档

社区

我们热爱讨论服务器端 Swift 和 Kitura,加入我们的 Slack 与团队见面吧!

许可证

此 Swift 包受 Apache 2.0 许可的许可。完整的许可文本可在 LICENSE 中找到。