- Added
onStop
future to Application.Running
. (#2061)
Application.runCommands()
was renamed to Application.start()
and no longer blocks until complete. Application.run()
now calls Application.start()
and waits for Application.running
's onStop
future to complete.
Note: This change makes it easier to test Application
since you can boot and start without needing a background thread.
- Added new
Services.global
method for registering application-wide singletons. (#2062)
With this addition, there are now three ways to register a service:
register
: This factory will be called each time the service is made.
singleton
: This factory will be called only once per container.
global
: This factory will be called only once per application.
Note that global services will be shared across event loops and must be thread-safe.
Below is an example usage of Services.global
for creating an application-wide memory cache.
final class MemoryCache {
var storage: [String: String]
var lock: Lock
init() {
self.storage = [:]
self.lock = .init()
}
func get(_ key: String) -> String? {
self.lock.lock()
defer { self.lock.unlock() }
return self.storage[key]
}
func set(_ key: String, to value: String?) {
self.lock.lock()
defer { self.lock.unlock() }
self.storage[key] = value
}
}
The service can be registered globally:
public func configure(_ s: inout Services) {
...
s.global(MemoryCache.self) { _ in
return .init()
}
}
The same instance of MemoryCache
is now shared across containers:
public func routes(_ r: Routes, _ c: Container) throws {
...
let cache = try c.make(MemoryCache.self)
r.get("cache", "get", ":key") { req -> String in
guard let key = req.parameters.get("key") else {
throw Abort(.internalServerError)
}
return "\(key) = \(cache.get(key) ?? "nil")"
}
r.get("cache", "set", ":key", ":value") { req -> String in
guard let key = req.parameters.get("key") else {
throw Abort(.internalServerError)
}
guard let value = req.parameters.get("value") else {
throw Abort(.internalServerError)
}
cache.set(key, to: value)
return "\(key) = \(value)"
}
}
This results in the cached values being accessible from across event loops.