I am using vapor framework for server side for my swift-tools-version:5.6.0
.package(url: "https://github.com/vapor/vapor.git", from: "4.75.0"),
.package(url: "https://github.com/vapor/fluent.git", from: "4.8.0"),
.package(url: "https://github.com/vapor/fluent-mysql-driver.git", from: "4.3.0"),
.package(url: "https://github.com/autimatisering/VaporSMTPKit.git", from: "1.0.4"),
I've been setup database using seperate class,
final class Database {
private(set) static var shared: Database!
static func initialize(_ db: FluentKit.Database) {
if let db = db as? MySQLDatabase {
self.shared = .init(db)
}
}
let db: MySQLDatabase
private init(_ db: MySQLDatabase) {
self.db = db
}
func query(_ query: String, with continuation: CheckedContinuation<[MySQLRow]?, Error>) {
self.db.query(query).whenComplete { result in
switch result {
case .success(let rows):
if rows.isEmpty {
continuation.resume(returning: nil)
} else {
continuation.resume(returning: rows)
}
case .failure(let error):
let error = error as NSError
print("Error: \(error)")
if error.code == 11 { // Disconnected
self.connect_db { error in
if let error = error {
continuation.resume(throwing: error)
} else {
self.query(query, with: continuation)
}
}
} else {
continuation.resume(throwing: error)
}
}
}
}
}
In the configure I init that class like, Also I saved the App
in the another class access by global.
app.databases.use(.mysql(configuration: .prod), as: .mysql)
do {
try await app.db.withConnection({ database in
Database.initialize(database)
})
} catch {
fatalError("Unable to connect database")
}
Meanwhile If the database server closed / terminated the connection, the vapor framework doesn't reconnect automatically. I really thought 'Modern Webservers will reconnect automatically instead of throwing connection closed error'. But vapor doesn't. I've tried to reconnect using below code
Using global App:
private func connect_db(_ completionHandler:@escaping(Error?) -> Void){
print("Reconnecting Database....")
Task.detached(priority: .userInitiated) {
do {
try kAPI.app.db.eventLoop.close()
try await kAPI.app.db.withConnection { database in
Database.initialize(database)
print("Connected")
completionHandler(nil)
}
} catch {
completionHandler(error)
}
}
}
Using Current Database:
private func connect_db(_ completionHandler:@escaping(Error?) -> Void){
print("Reconnecting Database....")
if let db = self.db as? FluentKit.Database {
Task.detached(priority: .userInitiated) {
do {
try await db.withConnection({ _ in
print("Connected")
completionHandler(nil)
})
} catch {
print("Unable to connect!")
completionHandler(error)
}
}
} else {
completionHandler(SERVER_ERROR("Invalid DB", info: "The Database isn't Database object", code: 28))
}
}
I got log Connected
& MySQLERROR: Connection Closed
continously. So the database isn't acutally connected but it completed the withConnection
closure without the error. Without DB reconnection all my work is gone to trash. DB reconnection is important for a webserver. Can anyone let me know what I am missing?
Is there any way that I can establish MySQL database reconnection in vapor framework? Thank you!