Add logging when reloading fails

This commit is contained in:
Gus Cairo 2025-05-07 11:30:50 +01:00
parent eb78ed3992
commit 8fbba2dd52
2 changed files with 31 additions and 8 deletions

View File

@ -266,6 +266,7 @@ var targets: [PackageDescription.Target] = [
.product(name: "SwiftASN1", package: "swift-asn1"), .product(name: "SwiftASN1", package: "swift-asn1"),
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"), .product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"), .product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
.product(name: "Logging", package: "swift-log"),
], ],
swiftSettings: strictConcurrencySettings swiftSettings: strictConcurrencySettings
), ),
@ -307,6 +308,7 @@ let package = Package(
.package(url: "https://github.com/apple/swift-asn1.git", from: "1.3.1"), .package(url: "https://github.com/apple/swift-asn1.git", from: "1.3.1"),
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.8.0"), .package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.8.0"),
.package(url: "https://github.com/apple/swift-async-algorithms.git", from: "1.0.0"), .package(url: "https://github.com/apple/swift-async-algorithms.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.6.3"),
], ],
targets: targets targets: targets

View File

@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
import AsyncAlgorithms import AsyncAlgorithms
import Logging
import NIOConcurrencyHelpers import NIOConcurrencyHelpers
import NIOSSL import NIOSSL
import ServiceLifecycle import ServiceLifecycle
@ -205,6 +206,7 @@ public struct TimedCertificateReloader: CertificateReloader {
private let certificateDescription: CertificateDescription private let certificateDescription: CertificateDescription
private let privateKeyDescription: PrivateKeyDescription private let privateKeyDescription: PrivateKeyDescription
private let state: NIOLockedValueBox<CertificateKeyPair?> private let state: NIOLockedValueBox<CertificateKeyPair?>
private let logger: Logger?
/// A `NIOSSLContextConfigurationOverride` that will be used as part of the NIO application's TLS configuration. /// A `NIOSSLContextConfigurationOverride` that will be used as part of the NIO application's TLS configuration.
/// Its certificate and private key will be kept up-to-date via the reload mechanism the ``TimedCertificateReloader`` /// Its certificate and private key will be kept up-to-date via the reload mechanism the ``TimedCertificateReloader``
@ -229,12 +231,14 @@ public struct TimedCertificateReloader: CertificateReloader {
public init( public init(
refreshInterval: TimeAmount, refreshInterval: TimeAmount,
certificateDescription: CertificateDescription, certificateDescription: CertificateDescription,
privateKeyDescription: PrivateKeyDescription privateKeyDescription: PrivateKeyDescription,
logger: Logger? = nil
) { ) {
self.init( self.init(
refreshInterval: Duration(refreshInterval), refreshInterval: Duration(refreshInterval),
certificateDescription: certificateDescription, certificateDescription: certificateDescription,
privateKeyDescription: privateKeyDescription privateKeyDescription: privateKeyDescription,
logger: logger
) )
} }
@ -248,12 +252,14 @@ public struct TimedCertificateReloader: CertificateReloader {
public init( public init(
refreshInterval: TimeAmount, refreshInterval: TimeAmount,
validatingCertificateDescription: CertificateDescription, validatingCertificateDescription: CertificateDescription,
validatingPrivateKeyDescription: PrivateKeyDescription validatingPrivateKeyDescription: PrivateKeyDescription,
logger: Logger? = nil
) throws { ) throws {
try self.init( try self.init(
refreshInterval: Duration(refreshInterval), refreshInterval: Duration(refreshInterval),
validatingCertificateDescription: validatingCertificateDescription, validatingCertificateDescription: validatingCertificateDescription,
validatingPrivateKeyDescription: validatingPrivateKeyDescription validatingPrivateKeyDescription: validatingPrivateKeyDescription,
logger: nil
) )
} }
@ -265,12 +271,14 @@ public struct TimedCertificateReloader: CertificateReloader {
public init( public init(
refreshInterval: Duration, refreshInterval: Duration,
certificateDescription: CertificateDescription, certificateDescription: CertificateDescription,
privateKeyDescription: PrivateKeyDescription privateKeyDescription: PrivateKeyDescription,
logger: Logger? = nil
) { ) {
self.refreshInterval = refreshInterval self.refreshInterval = refreshInterval
self.certificateDescription = certificateDescription self.certificateDescription = certificateDescription
self.privateKeyDescription = privateKeyDescription self.privateKeyDescription = privateKeyDescription
self.state = NIOLockedValueBox(nil) self.state = NIOLockedValueBox(nil)
self.logger = logger
// Immediately try to load the configured cert and key to avoid having to wait for the first // Immediately try to load the configured cert and key to avoid having to wait for the first
// reload loop to run. // reload loop to run.
@ -289,12 +297,14 @@ public struct TimedCertificateReloader: CertificateReloader {
public init( public init(
refreshInterval: Duration, refreshInterval: Duration,
validatingCertificateDescription: CertificateDescription, validatingCertificateDescription: CertificateDescription,
validatingPrivateKeyDescription: PrivateKeyDescription validatingPrivateKeyDescription: PrivateKeyDescription,
logger: Logger? = nil
) throws { ) throws {
self.refreshInterval = refreshInterval self.refreshInterval = refreshInterval
self.certificateDescription = validatingCertificateDescription self.certificateDescription = validatingCertificateDescription
self.privateKeyDescription = validatingPrivateKeyDescription self.privateKeyDescription = validatingPrivateKeyDescription
self.state = NIOLockedValueBox(nil) self.state = NIOLockedValueBox(nil)
self.logger = logger
// Immediately try to load the configured cert and key to avoid having to wait for the first // Immediately try to load the configured cert and key to avoid having to wait for the first
// reload loop to run. // reload loop to run.
@ -306,8 +316,19 @@ public struct TimedCertificateReloader: CertificateReloader {
/// - Important: You *must* call this method to get certificate and key updates. /// - Important: You *must* call this method to get certificate and key updates.
public func run() async throws { public func run() async throws {
for try await _ in AsyncTimerSequence.repeating(every: self.refreshInterval).cancelOnGracefulShutdown() { for try await _ in AsyncTimerSequence.repeating(every: self.refreshInterval).cancelOnGracefulShutdown() {
// We don't want to throw out of this method so simply ignore errors thrown from `reloadPair`. do {
try? self.reloadPair() try self.reloadPair()
} catch {
self.logger?.error(
"""
An unexpected error was encountered while trying to reload the certificate and \
private key pair.
""",
metadata: [
"error": error
]
)
}
} }
} }