An open API service indexing awesome lists of open source software.

https://github.com/swift-server/swift-service-lifecycle

Cleanly startup and shutdown server application, freeing resources in order before exiting.
https://github.com/swift-server/swift-service-lifecycle

Last synced: 8 months ago
JSON representation

Cleanly startup and shutdown server application, freeing resources in order before exiting.

Awesome Lists containing this project

README

          

# Swift Service Lifecycle

Swift Service Lifecycle provides a basic mechanism to cleanly start up and shut down an application, freeing resources in-order before exiting.
It also provides a `Signal`-based shutdown hook, to shut down on signals like `TERM` or `INT`.

Swift Service Lifecycle was designed with the idea that every application has some startup and shutdown workflow-like-logic which is often sensitive to failure and hard to get right.
The library encodes this common need in a safe and reusable way that is non-framework specific, and designed to be integrated with any server framework or directly in an application. Furthermore, it integrates natively with Structured Concurrency.

This is the beginning of a community-driven open-source project actively seeking [contributions](CONTRIBUTING.md), be it code, documentation, or ideas. What Swift Service Lifecycle provides today is covered in the [API docs](https://swiftpackageindex.com/swift-server/swift-service-lifecycle/main/documentation/servicelifecycle), but it will continue to evolve with community input.

## Getting started

Swift Service Lifecycle should be used if you have a server-side Swift application or a cross-platform (e.g. Linux, macOS) application, and you would like to manage its startup and shutdown lifecycle. Below you will find all you need to know to get started.

### Adding the dependency

To add a dependency on the package, declare it in your `Package.swift`:

```swift
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.0.0"),
```

and add `ServiceLifecycle` to the dependencies of your application target:

```swift
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle")
```

Example `Package.swift` file with `ServiceLifecycle` as a dependency:

```swift
// swift-tools-version:6.0
import PackageDescription

let package = Package(
name: "my-application",
dependencies: [
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.3.0"),
],
targets: [
.target(name: "MyApplication", dependencies: [
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle")
]),
.testTarget(name: "MyApplicationTests", dependencies: [
.target(name: "MyApplication"),
]),
]
)
```

### Using ServiceLifecycle

You can find a short usage example below. You can find more detailed
documentation on how to use ServiceLifecycle
[here](https://swiftpackageindex.com/swift-server/swift-service-lifecycle/main/documentation/servicelifecycle).

ServiceLifecycle consists of two main building blocks. The `Service` protocol and the `ServiceGroup`
actor. As a library or application developer you should model your long-running work as services
that implement the `Service` protocol. The protocol only requires the implementation of a single
`func run() async throws` method. Once implemented, your application you can use the `ServiceGroup`
to orchestrate multiple services. The group will spawn a child task for each service and call the
respective `run` method in the child task. Furthermore, the group will setup signal listeners for
the configured signals and trigger a graceful shutdown on each service.

```swift
import ServiceLifecycle
import Logging

// A service can be implemented by a struct, class or actor. For this example we are using a struct.
struct FooService: Service {
func run() async throws {
print("FooService starting")
try await Task.sleep(for: .seconds(10))
print("FooService done")
}
}

@main
struct Application {
static let logger = Logger(label: "Application")

static func main() async throws {
let service1 = FooService()
let service2 = FooService()

let serviceGroup = ServiceGroup(
services: [service1, service2],
gracefulShutdownSignals: [.sigterm],
logger: logger
)

try await serviceGroup.run()
}
}
```

## Security

Please see [SECURITY.md](SECURITY.md) for details on the security process.