Skip to content

Commit

Permalink
cleanup Lifecycle
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuawright11 committed Jul 16, 2024
1 parent 2b51325 commit 807a65b
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 258 deletions.
2 changes: 1 addition & 1 deletion Alchemy/AlchemyX/Router+Resource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extension Application {
) -> Self where R.Identifier: SQLValueConvertible & LosslessStringConvertible {
use(ResourceController<R>(db: db, tableName: table))
if updateTable {
Container.onStart {
Life.onStart {
try await db.updateSchema(R.self)
}
}
Expand Down
57 changes: 20 additions & 37 deletions Alchemy/Application/Lifecycle.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import NIOConcurrencyHelpers
import ServiceLifecycle

/// Manages the startup and shutdown of an Application as well as it's various
/// services and configurations.
actor Lifecycle {
public final class Lifecycle {
typealias Action = () async throws -> Void

fileprivate var startTasks: [Action] = []
Expand All @@ -13,6 +14,7 @@ actor Lifecycle {

private var group: ServiceGroup?
private var services: [ServiceLifecycle.Service] = []
private let lock = NIOLock()

init(app: Application) {
self.app = app
Expand All @@ -29,7 +31,7 @@ actor Lifecycle {
] + app.plugins
}

func start() async throws {
public func start() async throws {
app.container.register(self).singleton()

for plugin in plugins {
Expand All @@ -45,7 +47,7 @@ actor Lifecycle {
}
}

func shutdown() async throws {
public func shutdown() async throws {
for shutdown in shutdownTasks.reversed() {
try await shutdown()
}
Expand All @@ -55,25 +57,26 @@ actor Lifecycle {
}
}

func onStart(action: @escaping () async throws -> Void) {
self.startTasks.append(action)
public func onStart(action: @escaping () async throws -> Void) {
lock.withLock { startTasks.append(action) }
}

func onShutdown(action: @escaping () async throws -> Void) {
self.shutdownTasks.append(action)
public func onShutdown(action: @escaping () async throws -> Void) {
lock.withLock { shutdownTasks.append(action) }
}

func addService(_ service: ServiceLifecycle.Service) {
services.append(service)
public func addService(_ service: ServiceLifecycle.Service) {
lock.withLock { services.append(service) }
}

func start(args: [String]? = nil) async throws {
let commander = Container.require(Commander.self)
commander.setArgs(args)
let allServices = services + [commander]
let group = ServiceGroup(
public func start(args: [String]? = nil) async throws {
try await Container.require(Commander.self).runCommand(args: args)
}

public func runServices() async throws {
group = ServiceGroup(
configuration: ServiceGroupConfiguration(
services: allServices.map {
services: services.map {
.init(
service: $0,
successTerminationBehavior: .gracefullyShutdownGroup,
Expand All @@ -84,12 +87,10 @@ actor Lifecycle {
logger: Log
)
)

self.group = group
try await group.run()
try await group?.run()
}

func stop() async {
public func stop() async {
await group?.triggerGracefulShutdown()
}
}
Expand All @@ -99,21 +100,3 @@ extension Application {
container.require()
}
}

extension Container {
static var lifecycle: Lifecycle {
require()
}

public static func onStart(action: @escaping () async throws -> Void) {
Task { await lifecycle.onStart(action: action) }
}

public static func onShutdown(action: @escaping () async throws -> Void) {
Task { await lifecycle.onShutdown(action: action) }
}

public static func addService(_ service: ServiceLifecycle.Service) {
Task { await lifecycle.addService(service) }
}
}
13 changes: 1 addition & 12 deletions Alchemy/Command/Commander.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ServiceLifecycle

final class Commander: ServiceLifecycle.Service, @unchecked Sendable {
final class Commander {
/// Command to launch a given application.
private struct Launch: AsyncParsableCommand {
static var configuration: CommandConfiguration {
Expand All @@ -19,7 +19,6 @@ final class Commander: ServiceLifecycle.Service, @unchecked Sendable {
@Option(name: .shortAndLong) var log: Logger.Level? = nil
}

private var args: [String]?
private var commands: [Command.Type] = []
private var defaultCommand: Command.Type = ServeCommand.self

Expand All @@ -33,16 +32,6 @@ final class Commander: ServiceLifecycle.Service, @unchecked Sendable {
defaultCommand = command
}

func setArgs(_ value: [String]?) {
args = value
}

// MARK: Service

func run() async throws {
try await runCommand(args: args)
}

// MARK: Running Commands

/// Runs a command based on the given arguments. Returns the command that
Expand Down
112 changes: 0 additions & 112 deletions Alchemy/HTTP/ByteStream.swift

This file was deleted.

16 changes: 6 additions & 10 deletions Alchemy/HTTP/Bytes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,12 @@ public enum Bytes: ExpressibleByStringLiteral {
}

public static func stream<AS: AsyncSequence>(sequence: AS) -> Bytes where AS.Element == ByteBuffer {
.stream(
AsyncStream<ByteBuffer> { continuation in
Task {
for try await chunk in sequence {
continuation.yield(chunk)
}

continuation.finish()
}
.stream {
for try await chunk in sequence {
$0.write(chunk)
}
)

$0.finish()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,45 +53,19 @@ struct ServeCommand: Command {

// 3. start serving

try await buildHummingbirdApplication().run()
}

private func buildHummingbirdApplication() -> Hummingbird.Application<Responder> {
let address: BindAddress = if let socket {
.unixDomainSocket(path: socket)
} else {
.hostname(host, port: port)
}
return .init(
responder: Responder(
logResponses: !quiet
),
server: Container.require(Application.self).server,
configuration: ApplicationConfiguration(
address: address,
serverName: nil,
backlog: 256,
reuseAddress: false
),
onServerRunning: onServerStart,
eventLoopGroupProvider: .shared(LoopGroup),
logger: Log
@Inject var app: Application

app.addHTTPListener(
address: {
if let socket {
.unixDomainSocket(path: socket)
} else {
.hostname(host, port: port)
}
}(),
logResponses: !quiet
)
}

@Sendable private func onServerStart(channel: Channel) async {
if let unixSocket = socket {
Log.info("Server running on \(unixSocket).")
} else {
let link = "[http://\(host):\(port)]".bold
Log.info("Server running on \(link).")
}

if Env.isXcode {
Log.comment("Press Cmd+Period to stop the server")
} else {
Log.comment("Press Ctrl+C to stop the server".yellow)
print()
}
try await app.lifecycle.runServices()
}
}
Loading

0 comments on commit 807a65b

Please sign in to comment.