Introducing Swift Service Discovery

Yim Lee is an engineer on the Swift team at Apple, developing foundational server-side technologies with focus on distributed systems.

It is my pleasure to announce a new open source project for the Swift Server ecosystem, Swift Service Discovery. Service Discovery is a Swift package designed to establish a standard API that can be implemented by various service discovery backends such as DNS-based, key-value store, etc.

How does it work?

The Swift Service Discovery package defines the API only, similar to SwiftLog and SwiftMetrics; actual functionalities are provided by backend implementations.

Concepts

Server Applications

Application owners need to select a service discovery backend to make querying available. This is done by adding a dependency on the desired backend implementation and instantiating it at the beginning of the program.

For example, suppose the hypothetical DNSBasedServiceDiscovery is chosen as the backend:

// 1) Import the service discovery backend package
import DNSBasedServiceDiscovery

// 2) Create a concrete ServiceDiscovery object
let serviceDiscovery = DNSBasedServiceDiscovery()

To fetch the current list of instances (where result is Result<[Instance], Error>):

serviceDiscovery.lookup(service) { result in
    ...
}

To fetch the current list of instances (where result is Result<[Instance], Error>) AND subscribe to future changes:

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 returns a CancellationToken that can be used to cancel the subscription later on. onComplete is a closure that gets invoked when the subscription ends (e.g., when the service discovery instance shuts down) or gets cancelled through the CancellationToken. CompletionReason can be used to distinguish what led to the completion.

Backend Implementations

To become a compatible service discovery backend, implementations must conform to the ServiceDiscovery protocol which includes two methods: lookup and subscribe.

func lookup(
    _ service: Service,
    deadline: DispatchTime?,
    callback: @escaping (Result<[Instance], Error>) -> Void
)

lookup fetches the current list of instances for the given service and sends it to callback. If the service is unknown (e.g., registration is required but it has not been done for the service), then the result should be a LookupError.unknownService failure. A deadline should be imposed on when the operation will complete either via deadline or a default timeout.

func subscribe(
    to service: Service,
    onNext nextResultHandler: @escaping (Result<[Instance], Error>) -> Void,
    onComplete completionHandler: @escaping (CompletionReason) -> Void
) -> CancellationToken

subscribe “pushes” service instances to the nextResultHandler:

A new CancellationToken is created for each subscribe request. If the cancellation token’s isCancelled is true, the subscription has been cancelled and the backend implementation should cease calling the corresponding nextResultHandler.

The backend implementation must also notify via completionHandler when the subscription ends for any reason (e.g., the service discovery instance is shutting down or cancellation is requested through CancellationToken), so that the subscriber can submit another subscribe request if needed.

Project Status

This is the beginning of a community-driven open-source project actively seeking contributions. Besides contributing to Swift Service Discovery itself, we need compatible backend implementations that manage service registration and location information for querying.

Getting Involved

If you are interested in Swift Service Discovery, come and get involved! The source is available, and we encourage contributions from the open source community. If you have feedback, questions or would like to discuss the project, please feel free to chat on the Swift forums. If you would like to report bugs, please use the GitHub issue tracker. We look forward to working with you, and helping move the industry forward to a better, safer programming future.