Swift 的服务发现 API。
服务发现是指服务如何在分布式系统中找到彼此。 此 API 库旨在建立一个标准,该标准可以由各种服务发现后端实现,例如基于 DNS 的后端、Zookeeper 等键值存储。换句话说,此库仅定义 API,类似于 SwiftLog 和 SwiftMetrics;实际功能由后端实现提供。
这是一个社区驱动的开源项目的开始,积极寻求贡献,无论是代码、文档还是想法。除了为 SwiftServiceDiscovery 本身做出贡献之外,我们还需要与 SwiftServiceDiscovery 兼容的库,这些库管理服务注册和位置信息以进行查询。 API 文档中介绍了 SwiftServiceDiscovery 目前提供的功能,但它将随着社区的投入而不断发展。
如果您有一个服务器端 Swift 应用程序,并且想在同一系统中找到其他服务以发出 HTTP 请求或 RPC,那么 SwiftServiceDiscovery 正是适合您的库。 您将在下面找到入门所需的一切。
Service
表示后端实现中使用的标识类型。Instance
表示后端实现中使用的服务实例类型。注意:如果您正在构建一个库,则无需关心本节。您的库的最终用户(应用程序)将决定使用哪个服务发现后端。 库不应更改服务发现实现,因为这是应用程序拥有的。
SwiftServiceDiscovery 仅提供服务发现 API。 作为应用程序所有者,您需要选择一个服务发现后端才能进行查询。
选择后端的方法是添加对所需后端实现的依赖项,并在程序开始时实例化它。
例如,假设您已选择假设的 DNSBasedServiceDiscovery
作为后端
// 1) Import the service discovery backend package
import DNSBasedServiceDiscovery
// 2) Create a concrete ServiceDiscovery object
let serviceDiscovery = DNSBasedServiceDiscovery()
由于 API 刚刚启动,因此还没有很多实现。 如果您有兴趣实现一个,请参阅下面的“实现服务发现后端”部分,其中解释了如何进行操作。 与 SwiftServiceDiscovery API 兼容的现有库列表
要获取当前实例列表(其中 result
是 Result<[Instance], Error>
)
serviceDiscovery.lookup(service) { result in
...
}
要获取当前实例列表(其中 result
是 Result<[Instance], Error>
)并且订阅未来的更改
let cancellationToken = serviceDiscovery.subscribe(
to: service,
onNext: { result in
// This closure gets invoked once at the beginning and subsequently each time a change occurs
...
},
onComplete: { reason in
// This closure gets invoked when the subscription completes
...
}
)
...
// Cancel the `subscribe` request
cancellationToken.cancel()
subscribe
返回一个 CancellationToken
,您可以使用它来稍后取消订阅。 onComplete
是一个闭包,当订阅结束时(例如,当服务发现实例关闭时)或通过 CancellationToken
取消时,会调用该闭包。 CompletionReason
可用于区分导致完成的原因。
Async APIs 可用于 Swift 5.5 及更高版本。
要获取当前实例列表
let instances: [Instance] = try await serviceDiscovery.lookup(service)
要获取当前实例列表并且订阅未来的更改
for try await instances in serviceDiscovery.subscribe(to: service) {
// do something with this snapshot of instances
}
async subscribe
API 的底层是一个 AsyncSequence
。 要结束订阅,只需跳出 for
循环。
SwiftServiceDiscovery 包括用于常见要求的组合器,例如转换和过滤实例。 例如
// Only include instances running on port 8080
let serviceDiscovery = InMemoryServiceDiscovery(configuration: configuration)
.filterInstance { [8080].contains($0.port) }
注意:除非您需要实现自定义服务发现后端,否则本节中的所有内容可能都不相关,因此请随时跳过。
要添加对 API 包的依赖项,您需要在 Package.swift
中声明它
.package(url: "https://github.com/apple/swift-service-discovery.git", from: "1.3.0"),
并在您的库目标中,将“ServiceDiscovery”添加到您的依赖项
.target(
name: "MyServiceDiscovery",
dependencies: [
.product(name: "ServiceDiscovery", package: "swift-service-discovery"),
]
),
要成为所有 SwiftServiceDiscovery 使用者都可以使用的兼容服务发现后端,您需要实现一个符合 SwiftServiceDiscovery 提供的 ServiceDiscovery
协议的类型。 它包括两个方法,lookup
和 subscribe
。
/// Performs a lookup for the given service's instances. The result will be sent to `callback`.
///
/// `defaultLookupTimeout` will be used to compute `deadline` in case one is not specified.
///
/// - Parameters:
/// - service: The service to lookup
/// - deadline: Lookup is considered to have timed out if it does not complete by this time
/// - callback: The closure to receive lookup result
func lookup(_ service: Service, deadline: DispatchTime?, callback: @escaping (Result<[Instance], Error>) -> Void)
lookup
获取给定服务的当前实例列表,并将其发送到 callback
。 如果该服务未知(例如,需要注册但尚未为该服务完成注册),则结果应为 LookupError.unknownService
失败。
后端实现应强制执行操作完成的时间限制。 如果给出了 deadline
,则应遵守它,否则应使用 defaultLookupTimeout
计算一个。
/// Subscribes to receive a service's instances whenever they change.
///
/// The service's current list of instances will be sent to `nextResultHandler` when this method is first called. Subsequently,
/// `nextResultHandler` will only be invoked when the `service`'s instances change.
///
/// ### Threading
///
/// `nextResultHandler` and `completionHandler` may be invoked on arbitrary threads, as determined by implementation.
///
/// - Parameters:
/// - service: The service to subscribe to
/// - nextResultHandler: The closure to receive update result
/// - completionHandler: The closure to invoke when the subscription completes (e.g., when the `ServiceDiscovery` instance exits, etc.),
/// including cancellation requested through `CancellationToken`.
///
/// - Returns: A `CancellationToken` instance that can be used to cancel the subscription in the future.
func subscribe(to service: Service, onNext nextResultHandler: @escaping (Result<[Instance], Error>) -> Void, onComplete completionHandler: @escaping (CompletionReason) -> Void) -> CancellationToken
subscribe
将服务实例“推送”到 nextResultHandler
。 后端实现应调用 nextResultHandler
subscribe
时,调用者应收到给定服务的当前实例列表。 这本质上是 lookup
结果。nextResultHandler
。必须为每个 subscribe
请求创建一个新的 CancellationToken
。 如果取消令牌的 isCancelled
为 true
,则订阅已被取消,并且后端实现应停止调用相应的 nextResultHandler
。
后端实现还必须通过 completionHandler
通知订阅何时因任何原因结束(例如,服务发现实例正在关闭或通过 CancellationToken
请求取消),以便订阅者可以根据需要提交另一个 subscribe
请求。
请随时通过 https://forums.swift.org/c/server 与我们联系。