mirror of
https://github.com/swift-server/swift-aws-lambda-runtime.git
synced 2026-05-03 07:22:27 +00:00
e58d89148c
- Adjust notice, security reporting, code of conduct, contribution process to the standard AWS documents - Adjust GitHub issue templates to AWS standard ones. - Adjust the license header in all source files --------- Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
192 lines
6.7 KiB
Swift
192 lines
6.7 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the SwiftAWSLambdaRuntime open source project
|
|
//
|
|
// Copyright SwiftAWSLambdaRuntime project authors
|
|
// Copyright (c) Amazon.com, Inc. or its affiliates.
|
|
// Licensed under Apache License v2.0
|
|
//
|
|
// See LICENSE.txt for license information
|
|
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#if os(macOS)
|
|
import Darwin.C
|
|
#elseif canImport(Glibc)
|
|
import Glibc
|
|
#elseif canImport(Musl)
|
|
import Musl
|
|
#elseif os(Windows)
|
|
import ucrt
|
|
#else
|
|
#error("Unsupported platform")
|
|
#endif
|
|
|
|
/// A clock implementation based on Unix epoch time for AWS Lambda runtime operations.
|
|
///
|
|
/// `LambdaClock` provides millisecond-precision timing based on the Unix epoch
|
|
/// (January 1, 1970, 00:00:00 UTC). This clock is designed for Lambda runtime
|
|
/// operations where precise wall-clock time is required.
|
|
///
|
|
/// ## Usage
|
|
///
|
|
/// ```swift
|
|
/// let clock = LambdaClock()
|
|
/// let now = clock.now
|
|
/// let deadline = now.advanced(by: .seconds(30))
|
|
///
|
|
/// // Sleep until deadline
|
|
/// try await clock.sleep(until: deadline)
|
|
/// ```
|
|
///
|
|
/// ## Performance
|
|
///
|
|
/// This clock uses `clock_gettime(CLOCK_REALTIME)` on Unix systems for
|
|
/// high-precision wall-clock time measurement with millisecond resolution.
|
|
///
|
|
/// ## TimeZone Handling
|
|
///
|
|
/// The Lambda execution environment uses UTC as a timezone,
|
|
/// `LambdaClock` operates in UTC and does not account for time zones.
|
|
/// see: TZ in https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html
|
|
@available(LambdaSwift 2.0, *)
|
|
public struct LambdaClock: Clock {
|
|
public typealias Duration = Swift.Duration
|
|
|
|
/// A moment in time represented as milliseconds since the Unix epoch.
|
|
///
|
|
/// `Instant` represents a specific point in time as the number of milliseconds
|
|
/// that have elapsed since January 1, 1970, 00:00:00 UTC (Unix epoch).
|
|
///
|
|
/// ## Thread Safety
|
|
///
|
|
/// `Instant` is a value type and is inherently thread-safe.
|
|
public struct Instant: InstantProtocol, CustomStringConvertible {
|
|
/// The number of milliseconds since the Unix epoch.
|
|
let instant: Int64
|
|
|
|
public typealias Duration = Swift.Duration
|
|
|
|
/// Creates a new instant by adding a duration to this instant.
|
|
///
|
|
/// - Parameter duration: The duration to add to this instant.
|
|
/// - Returns: A new instant advanced by the specified duration.
|
|
///
|
|
/// ## Example
|
|
///
|
|
/// ```swift
|
|
/// let now = LambdaClock().now
|
|
/// let future = now.advanced(by: .seconds(30))
|
|
/// ```
|
|
public func advanced(by duration: Duration) -> Instant {
|
|
.init(millisecondsSinceEpoch: Int64(instant + Int64(duration / .milliseconds(1))))
|
|
}
|
|
|
|
/// Calculates the duration between this instant and another instant.
|
|
///
|
|
/// - Parameter other: The target instant to calculate duration to.
|
|
/// - Returns: The duration from this instant to the other instant.
|
|
/// Positive if `other` is in the future, negative if in the past.
|
|
///
|
|
/// ## Example
|
|
///
|
|
/// ```swift
|
|
/// let start = LambdaClock().now
|
|
/// // ... some work ...
|
|
/// let end = LambdaClock().now
|
|
/// let elapsed = start.duration(to: end)
|
|
/// ```
|
|
public func duration(to other: Instant) -> Duration {
|
|
.milliseconds(other.instant - self.instant)
|
|
}
|
|
|
|
/// Compares two instants for ordering.
|
|
///
|
|
/// - Parameters:
|
|
/// - lhs: The left-hand side instant.
|
|
/// - rhs: The right-hand side instant.
|
|
/// - Returns: `true` if `lhs` represents an earlier time than `rhs`.
|
|
public static func < (lhs: Instant, rhs: Instant) -> Bool {
|
|
lhs.instant < rhs.instant
|
|
}
|
|
|
|
/// Returns this instant as the number of milliseconds since the Unix epoch.
|
|
/// - Returns: The number of milliseconds since the Unix epoch.
|
|
public func millisecondsSinceEpoch() -> Int64 {
|
|
self.instant
|
|
}
|
|
|
|
/// Creates an instant from milliseconds since the Unix epoch.
|
|
/// - Parameter milliseconds: The number of milliseconds since the Unix epoch.
|
|
public init(millisecondsSinceEpoch milliseconds: Int64) {
|
|
self.instant = milliseconds
|
|
}
|
|
|
|
/// Renders an Instant as an EPOCH value
|
|
public var description: String {
|
|
"\(self.instant)"
|
|
}
|
|
}
|
|
|
|
/// The current instant according to this clock.
|
|
///
|
|
/// This property returns the current wall-clock time as milliseconds
|
|
/// since the Unix epoch.
|
|
/// This method uses `clock_gettime(CLOCK_REALTIME)` to obtain high-precision
|
|
/// wall-clock time.
|
|
///
|
|
/// - Returns: An `Instant` representing the current time.
|
|
public var now: Instant {
|
|
var ts = timespec()
|
|
clock_gettime(CLOCK_REALTIME, &ts)
|
|
return .init(millisecondsSinceEpoch: Int64(ts.tv_sec) * 1000 + Int64(ts.tv_nsec) / 1_000_000)
|
|
}
|
|
|
|
/// The minimum resolution of this clock.
|
|
///
|
|
/// `LambdaClock` provides millisecond resolution.
|
|
public var minimumResolution: Duration {
|
|
.milliseconds(1)
|
|
}
|
|
|
|
/// Suspends the current task until the specified deadline.
|
|
///
|
|
/// - Parameters:
|
|
/// - deadline: The instant until which to sleep.
|
|
/// - tolerance: The allowed tolerance for the sleep duration. Currently unused.
|
|
///
|
|
/// - Throws: `CancellationError` if the task is cancelled during sleep.
|
|
///
|
|
/// ## Example
|
|
///
|
|
/// ```swift
|
|
/// let clock = LambdaClock()
|
|
/// let deadline = clock.now.advanced(by: .seconds(5))
|
|
/// try await clock.sleep(until: deadline)
|
|
/// ```
|
|
public func sleep(until deadline: Instant, tolerance: Instant.Duration?) async throws {
|
|
let now = self.now
|
|
let sleepDuration = now.duration(to: deadline)
|
|
if sleepDuration > .zero {
|
|
try await ContinuousClock().sleep(for: sleepDuration)
|
|
}
|
|
}
|
|
|
|
/// Hardcoded maximum execution time for a Lambda function.
|
|
public static var maxLambdaExecutionTime: Duration {
|
|
// 15 minutes in milliseconds
|
|
// see https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html
|
|
.milliseconds(15 * 60 * 1000)
|
|
}
|
|
|
|
/// Returns the maximum deadline for a Lambda function execution.
|
|
/// This is the current time plus the maximum execution time.
|
|
/// This function is only used by the local server for testing purposes.
|
|
public static var maxLambdaDeadline: Instant {
|
|
LambdaClock().now.advanced(by: maxLambdaExecutionTime)
|
|
}
|
|
}
|