Skip to content

Commit 2e04511

Browse files
authored
move config, lifecycle, context to separate files (#32)
motivation: easier code navigation changes: move config, lifecycle, context to separate source files
1 parent a051851 commit 2e04511

12 files changed

+307
-252
lines changed

Sources/SwiftAwsLambda/Lambda.swift

Lines changed: 0 additions & 244 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ import Darwin.C
1919
#endif
2020

2121
import Backtrace
22-
import Dispatch
2322
import Logging
2423
import NIO
25-
import NIOConcurrencyHelpers
2624

2725
public enum Lambda {
2826
/// Run a Lambda defined by implementing the `LambdaClosure` closure.
@@ -113,248 +111,6 @@ public enum Lambda {
113111
signalSource.cancel()
114112
}
115113
}
116-
117-
public class Context {
118-
/// The request ID, which identifies the request that triggered the function invocation.
119-
public let requestId: String
120-
121-
/// The AWS X-Ray tracing header.
122-
public let traceId: String
123-
124-
/// The ARN of the Lambda function, version, or alias that's specified in the invocation.
125-
public let invokedFunctionArn: String
126-
127-
/// The timestamp that the function times out
128-
public let deadline: DispatchWallTime
129-
130-
/// For invocations from the AWS Mobile SDK, data about the Amazon Cognito identity provider.
131-
public let cognitoIdentity: String?
132-
133-
/// For invocations from the AWS Mobile SDK, data about the client application and device.
134-
public let clientContext: String?
135-
136-
/// a logger to log
137-
public let logger: Logger
138-
139-
internal init(requestId: String,
140-
traceId: String,
141-
invokedFunctionArn: String,
142-
deadline: DispatchWallTime,
143-
cognitoIdentity: String? = nil,
144-
clientContext: String? = nil,
145-
logger: Logger) {
146-
self.requestId = requestId
147-
self.traceId = traceId
148-
self.invokedFunctionArn = invokedFunctionArn
149-
self.cognitoIdentity = cognitoIdentity
150-
self.clientContext = clientContext
151-
self.deadline = deadline
152-
// mutate logger with context
153-
var logger = logger
154-
logger[metadataKey: "awsRequestId"] = .string(requestId)
155-
logger[metadataKey: "awsTraceId"] = .string(traceId)
156-
self.logger = logger
157-
}
158-
159-
public func getRemainingTime() -> TimeAmount {
160-
let deadline = self.deadline.millisSinceEpoch
161-
let now = DispatchWallTime.now().millisSinceEpoch
162-
163-
let remaining = deadline - now
164-
return .milliseconds(remaining)
165-
}
166-
}
167-
168-
private final class Lifecycle {
169-
private let eventLoop: EventLoop
170-
private let logger: Logger
171-
private let configuration: Configuration
172-
private let factory: LambdaHandlerFactory
173-
174-
private var _state = State.idle
175-
private let stateLock = Lock()
176-
177-
init(eventLoop: EventLoop, logger: Logger, configuration: Configuration, factory: @escaping LambdaHandlerFactory) {
178-
self.eventLoop = eventLoop
179-
self.logger = logger
180-
self.configuration = configuration
181-
self.factory = factory
182-
}
183-
184-
deinit {
185-
guard case .shutdown = self.state else {
186-
preconditionFailure("invalid state \(self.state)")
187-
}
188-
}
189-
190-
private var state: State {
191-
get {
192-
return self.stateLock.withLock {
193-
self._state
194-
}
195-
}
196-
set {
197-
self.stateLock.withLockVoid {
198-
precondition(newValue.order > _state.order, "invalid state \(newValue) after \(self._state)")
199-
self._state = newValue
200-
}
201-
}
202-
}
203-
204-
func start() -> EventLoopFuture<Int> {
205-
logger.info("lambda lifecycle starting with \(self.configuration)")
206-
self.state = .initializing
207-
var logger = self.logger
208-
logger[metadataKey: "lifecycleId"] = .string(self.configuration.lifecycle.id)
209-
let runner = LambdaRunner(eventLoop: self.eventLoop, configuration: self.configuration)
210-
return runner.initialize(logger: logger, factory: self.factory).flatMap { handler in
211-
self.state = .active(runner, handler)
212-
return self.run()
213-
}
214-
}
215-
216-
func stop() {
217-
self.logger.debug("lambda lifecycle stopping")
218-
self.state = .stopping
219-
}
220-
221-
func shutdown() {
222-
self.logger.debug("lambda lifecycle shutdown")
223-
self.state = .shutdown
224-
}
225-
226-
@inline(__always)
227-
private func run() -> EventLoopFuture<Int> {
228-
let promise = self.eventLoop.makePromise(of: Int.self)
229-
230-
func _run(_ count: Int) {
231-
switch self.state {
232-
case .active(let runner, let handler):
233-
if self.configuration.lifecycle.maxTimes > 0, count >= self.configuration.lifecycle.maxTimes {
234-
return promise.succeed(count)
235-
}
236-
var logger = self.logger
237-
logger[metadataKey: "lifecycleIteration"] = "\(count)"
238-
runner.run(logger: logger, handler: handler).whenComplete { result in
239-
switch result {
240-
case .success:
241-
// recursive! per aws lambda runtime spec the polling requests are to be done one at a time
242-
_run(count + 1)
243-
case .failure(let error):
244-
promise.fail(error)
245-
}
246-
}
247-
case .stopping, .shutdown:
248-
promise.succeed(count)
249-
default:
250-
preconditionFailure("invalid run state: \(self.state)")
251-
}
252-
}
253-
254-
_run(0)
255-
256-
return promise.futureResult
257-
}
258-
259-
private enum State {
260-
case idle
261-
case initializing
262-
case active(LambdaRunner, LambdaHandler)
263-
case stopping
264-
case shutdown
265-
266-
internal var order: Int {
267-
switch self {
268-
case .idle:
269-
return 0
270-
case .initializing:
271-
return 1
272-
case .active:
273-
return 2
274-
case .stopping:
275-
return 3
276-
case .shutdown:
277-
return 4
278-
}
279-
}
280-
}
281-
}
282-
283-
@usableFromInline
284-
internal struct Configuration: CustomStringConvertible {
285-
let general: General
286-
let lifecycle: Lifecycle
287-
let runtimeEngine: RuntimeEngine
288-
289-
@usableFromInline
290-
init() {
291-
self.init(general: .init(), lifecycle: .init(), runtimeEngine: .init())
292-
}
293-
294-
init(general: General? = nil, lifecycle: Lifecycle? = nil, runtimeEngine: RuntimeEngine? = nil) {
295-
self.general = general ?? General()
296-
self.lifecycle = lifecycle ?? Lifecycle()
297-
self.runtimeEngine = runtimeEngine ?? RuntimeEngine()
298-
}
299-
300-
struct General: CustomStringConvertible {
301-
let logLevel: Logger.Level
302-
303-
init(logLevel: Logger.Level? = nil) {
304-
self.logLevel = logLevel ?? env("LOG_LEVEL").flatMap(Logger.Level.init) ?? .info
305-
}
306-
307-
var description: String {
308-
return "\(General.self)(logLevel: \(self.logLevel))"
309-
}
310-
}
311-
312-
struct Lifecycle: CustomStringConvertible {
313-
let id: String
314-
let maxTimes: Int
315-
let stopSignal: Signal
316-
317-
init(id: String? = nil, maxTimes: Int? = nil, stopSignal: Signal? = nil) {
318-
self.id = id ?? "\(DispatchTime.now().uptimeNanoseconds)"
319-
self.maxTimes = maxTimes ?? env("MAX_REQUESTS").flatMap(Int.init) ?? 0
320-
self.stopSignal = stopSignal ?? env("STOP_SIGNAL").flatMap(Int32.init).flatMap(Signal.init) ?? Signal.TERM
321-
precondition(self.maxTimes >= 0, "maxTimes must be equal or larger than 0")
322-
}
323-
324-
var description: String {
325-
return "\(Lifecycle.self)(id: \(self.id), maxTimes: \(self.maxTimes), stopSignal: \(self.stopSignal))"
326-
}
327-
}
328-
329-
struct RuntimeEngine: CustomStringConvertible {
330-
let ip: String
331-
let port: Int
332-
let keepAlive: Bool
333-
let requestTimeout: TimeAmount?
334-
let offload: Bool
335-
336-
init(baseURL: String? = nil, keepAlive: Bool? = nil, requestTimeout: TimeAmount? = nil, offload: Bool? = nil) {
337-
let ipPort = env("AWS_LAMBDA_RUNTIME_API")?.split(separator: ":") ?? ["127.0.0.1", "7000"]
338-
guard ipPort.count == 2, let port = Int(ipPort[1]) else {
339-
preconditionFailure("invalid ip+port configuration \(ipPort)")
340-
}
341-
self.ip = String(ipPort[0])
342-
self.port = port
343-
self.keepAlive = keepAlive ?? env("KEEP_ALIVE").flatMap(Bool.init) ?? true
344-
self.requestTimeout = requestTimeout ?? env("REQUEST_TIMEOUT").flatMap(Int64.init).flatMap { .milliseconds($0) }
345-
self.offload = offload ?? env("OFFLOAD").flatMap(Bool.init) ?? false
346-
}
347-
348-
var description: String {
349-
return "\(RuntimeEngine.self)(ip: \(self.ip), port: \(self.port), keepAlive: \(self.keepAlive), requestTimeout: \(String(describing: self.requestTimeout)), offload: \(self.offload)"
350-
}
351-
}
352-
353-
@usableFromInline
354-
var description: String {
355-
return "\(Configuration.self)\n \(self.general))\n \(self.lifecycle)\n \(self.runtimeEngine)"
356-
}
357-
}
358114
}
359115

360116
public typealias LambdaResult = Result<[UInt8], Error>
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftAwsLambda open source project
4+
//
5+
// Copyright (c) 2017-2020 Apple Inc. and the SwiftAwsLambda project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftAwsLambda project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Dispatch
16+
import Logging
17+
import NIO
18+
19+
extension Lambda {
20+
@usableFromInline
21+
internal struct Configuration: CustomStringConvertible {
22+
let general: General
23+
let lifecycle: Lifecycle
24+
let runtimeEngine: RuntimeEngine
25+
26+
@usableFromInline
27+
init() {
28+
self.init(general: .init(), lifecycle: .init(), runtimeEngine: .init())
29+
}
30+
31+
init(general: General? = nil, lifecycle: Lifecycle? = nil, runtimeEngine: RuntimeEngine? = nil) {
32+
self.general = general ?? General()
33+
self.lifecycle = lifecycle ?? Lifecycle()
34+
self.runtimeEngine = runtimeEngine ?? RuntimeEngine()
35+
}
36+
37+
struct General: CustomStringConvertible {
38+
let logLevel: Logger.Level
39+
40+
init(logLevel: Logger.Level? = nil) {
41+
self.logLevel = logLevel ?? env("LOG_LEVEL").flatMap(Logger.Level.init) ?? .info
42+
}
43+
44+
var description: String {
45+
return "\(General.self)(logLevel: \(self.logLevel))"
46+
}
47+
}
48+
49+
struct Lifecycle: CustomStringConvertible {
50+
let id: String
51+
let maxTimes: Int
52+
let stopSignal: Signal
53+
54+
init(id: String? = nil, maxTimes: Int? = nil, stopSignal: Signal? = nil) {
55+
self.id = id ?? "\(DispatchTime.now().uptimeNanoseconds)"
56+
self.maxTimes = maxTimes ?? env("MAX_REQUESTS").flatMap(Int.init) ?? 0
57+
self.stopSignal = stopSignal ?? env("STOP_SIGNAL").flatMap(Int32.init).flatMap(Signal.init) ?? Signal.TERM
58+
precondition(self.maxTimes >= 0, "maxTimes must be equal or larger than 0")
59+
}
60+
61+
var description: String {
62+
return "\(Lifecycle.self)(id: \(self.id), maxTimes: \(self.maxTimes), stopSignal: \(self.stopSignal))"
63+
}
64+
}
65+
66+
struct RuntimeEngine: CustomStringConvertible {
67+
let ip: String
68+
let port: Int
69+
let keepAlive: Bool
70+
let requestTimeout: TimeAmount?
71+
let offload: Bool
72+
73+
init(baseURL: String? = nil, keepAlive: Bool? = nil, requestTimeout: TimeAmount? = nil, offload: Bool? = nil) {
74+
let ipPort = env("AWS_LAMBDA_RUNTIME_API")?.split(separator: ":") ?? ["127.0.0.1", "7000"]
75+
guard ipPort.count == 2, let port = Int(ipPort[1]) else {
76+
preconditionFailure("invalid ip+port configuration \(ipPort)")
77+
}
78+
self.ip = String(ipPort[0])
79+
self.port = port
80+
self.keepAlive = keepAlive ?? env("KEEP_ALIVE").flatMap(Bool.init) ?? true
81+
self.requestTimeout = requestTimeout ?? env("REQUEST_TIMEOUT").flatMap(Int64.init).flatMap { .milliseconds($0) }
82+
self.offload = offload ?? env("OFFLOAD").flatMap(Bool.init) ?? false
83+
}
84+
85+
var description: String {
86+
return "\(RuntimeEngine.self)(ip: \(self.ip), port: \(self.port), keepAlive: \(self.keepAlive), requestTimeout: \(String(describing: self.requestTimeout)), offload: \(self.offload)"
87+
}
88+
}
89+
90+
@usableFromInline
91+
var description: String {
92+
return "\(Configuration.self)\n \(self.general))\n \(self.lifecycle)\n \(self.runtimeEngine)"
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)