Swift Digest
Blog | Swift.org Blog

Swift Service Lifecycle の発表

Introducing Swift Service Lifecycle

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

この記事の要点

何が発表されたのか

Swift Service Lifecycle は、サーバーアプリケーション(サービスとも呼ばれます)の起動と終了の流れを管理するための Swift パッケージです。

多くのサービスには、起動・終了にまつわるワークフローのロジックがあります。起動時にはスレッドプールの初期化、データマイグレーションの実行、キャッシュのウォームアップなど、トラフィックやイベントを受け付ける前の状態初期化が必要です。終了時には、ファイルディスクリプタやその他のシステムリソースを正しく解放しないとリークしてしまうため、それらを片付ける処理が必要です。これらの処理は失敗の影響を受けやすく、正しく実装するのが難しいとされています。

従来は、サーバーアプリケーションやフレームワークがそれぞれ独自にこの課題へ対処する必要があり、ミスが起きやすい状況でした。Service Lifecycle は、この共通の必要性を安全・再利用可能・フレームワーク非依存な形でコード化します。任意のサーバーフレームワークと統合したり、サーバーアプリケーションの main に直接組み込んだりして使えるように設計されています。

何に使えるのか

推奨される使い方は、サーバーアプリケーションの mainServiceLifecycle のインスタンスを作り、そこに LifecycleTasks を登録するというものです。start を呼ぶと、登録された順番にタスクが起動されます。

既定では、ServiceLifecycleINTTERM を捕捉する Signal ハンドラも登録します。これらは、最近のデプロイ環境で終了要求を伝えるために使われる典型的なシグナルです。シグナルを捕捉すると終了シーケンスが始まり、LifecycleTasks は登録とは逆の順番で終了されます。

次の例は、mainServiceLifecycle を構成する一連の流れを示しています。

// パッケージをインポートする
import Lifecycle

// Lifecycle コンテナを初期化する
var lifecycle = ServiceLifecycle()

// アプリケーション終了時にシャットダウンすべきリソースを登録する
//
// この例では SwiftNIO の EventLoopGroup を登録し、
// シャットダウン時に呼ばれる syncShutdownGracefully を渡している
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
lifecycle.registerShutdown(
    name: "eventLoopGroup",
    .sync(eventLoopGroup.syncShutdownGracefully)
)

// アプリケーション起動時に開始し、終了時にシャットダウンすべき
// リソースを登録する
//
// この例では DatabaseMigrator を登録し、
// 起動時に呼ばれる migrate とシャットダウン時に呼ばれる shutdown を渡している
let migrator = DatabaseMigrator(eventLoopGroup: eventLoopGroup)
lifecycle.register(
    name: "migrator",
    start: .async(migrator.migrate),
    shutdown: .async(migrator.shutdown)
)

// アプリケーションを起動する
//
// register で渡した起動ハンドラは、登録した順番で呼ばれる
lifecycle.start() { error in
    // 起動完了ハンドラ
    // 起動時にエラーが発生した場合はここで受け取れる
    if let error = error {
        logger.error("failed starting \(self) ☠️: \(error)")
    } else {
        logger.info("\(self) started successfully 🚀")
    }
}

// アプリケーションの終了を待つ
//
// これはブロッキング操作で、通常は Signal を待つ
// Signal は lifecycle.init で設定でき、既定では INT と TERM
// register / registerShutdown で渡したシャットダウンハンドラは、
// 登録とは逆の順番で呼ばれる
lifecycle.wait()

registerShutdown は終了時の処理だけを登録し、register は起動と終了の両方の処理を登録します。起動ハンドラは登録順に、シャットダウンハンドラは逆順に呼ばれるため、依存関係のあるリソースを正しい順序で初期化・解放できます。

導入・今後の位置づけ

Service Lifecycle はオープンソースプロジェクトであり、コミュニティからの貢献を歓迎しているとされています。ソースコードは GitHub リポジトリで公開されており、フィードバックや議論は Swift フォーラムの server カテゴリで行えます。

関連リンク