-
-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PostgresNIO/ListenStateMachine.swift:182: Fatal error: Invalid state: initialized #458
Comments
@CrownedPhoenix Thank you for the bug report. In order to prioritize this, what do you want to achieve? Above code very much looks like it is geared towards reproducing the issue. To achieve your use-case can you use the new async listen API? Maybe in connection with the new The code should look like this: @_spi(ConnectionPool) import PostgresNIO
import Logging
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
enum App {
static func main() async throws {
let logger = Logger(label: "test")
let configuration = PostgresClient.Configuration(
host: "localhost",
username: "postgres",
password: "postgres",
database: "test",
tls: .disable
)
let client = PostgresClient(configuration: configuration, backgroundLogger: logger)
await withTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask {
await client.run()
}
do {
try await client.withConnection { connection in
for try await message in try await connection.listen("default") {
// you will stay forever in this loop, until you break out of it!
logger.info("Message received", metadata: ["message": "\(message)"])
}
}
} catch {
logger.error("Error happened", metadata: ["error": "String(reflecting: error)"])
}
taskGroup.cancelAll() // shutdown postgres client when done
}
}
} If you have any questions please feel free to reach out. |
Yeah - the reproducer I provided was mainly to simulate an error that I'm running into in practice in my test setup. It just depends on whether the All said, I'll give the code changes you suggest here a try with the reproducer and then see if replicating them in my own test cases will resolve the issue for me. |
Generally I thought the state should not be reachable. For this reason, I consider this a There is lot's to unpack in the code you provided and certain issues are foreseeable. This is why I provided you the code to show you, how I recommend to use PostgresNIO's listening support. |
Totally understand that - if I can find a solution that doesn't require you to change anything that will be great for me as well. In the meantime, do you have any idea why |
Oh I need to do the @_spi thing I bet. Sorry i missed that. |
Yeah. We intend to drop the requirement to use |
|
Alright, it looks like using PostgresClient resolves this issue. extension EventLoopGroupConnectionPool where Source == PostgresConnectionSource {
public func database(logger: Logger) -> any PostgresDatabase {
_EventLoopGroupConnectionPoolPostgresDatabase(pool: self, logger: logger)
}
} The analogous code with try await client.withConnection({ $0.sql() }) Because of this there's a bunch of places where I depend on synchronous behavior that I'd have to change to async - which is doable just large scale in my case unfortunately. I am interested in pursuing the use of |
I've been diving into this issue a bit recently as well, and I think the root of the issue is that @CrownedPhoenix is using |
@NeedleInAJayStack makes an important point. At any rate, I would expect different error behavior if PGNIO wasn't able to fulfill the listen request. |
@CrownedPhoenix This is why I removed that #466, fixes this issue. But I have now an easy way to replicate it :) |
Oh good call - thanks for un-fixing. I totally agree that we ought to better protect against the fatalError case too. |
Description
ListenStateMachine reaches an invalid state during concurrent operation of
addListener
on a pool that is shutting down.I'm not sure if this behavior is expected given the obvious concurrent execution described in the reproducer below.
At any rate, a fatalError here seems out of place unless there's something I'm misunderstanding about the ListenStateMachine.
To Reproduce
Simply run the following:
with the following dependencies:
and the following for the database setup:
the result will be:
Expected behavior
My assumption about the behavior for the code would simply be that once the EventLoopGroupConnectionPool gracefully shuts down, all outstanding listeners created with
addListener
would be cleaned up or closed since the connections they are listening on have been shutdown.Environment
swift package init
from the terminalThe text was updated successfully, but these errors were encountered: