-
-
Notifications
You must be signed in to change notification settings - Fork 82
Make backend key data optional #296
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for bringing this up! I think this is something that we should definitely support. However, I think, we should make all of this way more explicit than currently proposed:
- We should add a setting to
PostgresConnection.Configuration.Conntection
that allow connections to not provideBackendKeyData
. A possible name should be:allowNotProvidingBackendKeyData
. By default this property should be set to false. - We need to inject the value of the property into the StateMachine.
- If we receive
readyForQuery
without having receivedbackendKeyData
before, we should check, if the propertyallowNotProvidingBackendKeyData
is true and only progress in this case. - We need unit test cases that cover both flows.
Is this something you feel comfortable tackling? I'm here to help you at any step on the way.
Can do. I'll work on those changes. Thanks! |
I made some changes so that connections must provide |
Actually, handling this in the unit tests was straightforward, so I went ahead and updated it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This already looks really good. Don't get distracted by the amount of code comments... This is awesome work!
Would you mind addressing the comments and add a test case for the new code path in ConnectionStateMachineTests.swift
?
Two examples tests are here:
func testBackendKeyAndParameterStatusReceivedAfterAuthenticated() {
var state = ConnectionStateMachine(.authenticated(nil, [:]))
XCTAssertEqual(state.backendKeyDataReceived(.init(processID: 2730, secretKey: 882037977)), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "DateStyle", value: "ISO, MDY")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "application_name", value: "")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "server_encoding", value: "UTF8")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "integer_datetimes", value: "on")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "client_encoding", value: "UTF8")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "TimeZone", value: "Etc/UTC")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "is_superuser", value: "on")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "server_version", value: "13.1 (Debian 13.1-1.pgdg100+1)")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "session_authorization", value: "postgres")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "IntervalStyle", value: "postgres")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "standard_conforming_strings", value: "on")), .wait)
XCTAssertEqual(state.readyForQueryReceived(.idle), .fireEventReadyForQuery)
}
func testReadyForQueryReceivedWithoutBackendKeyAfterAuthenticated() {
var state = ConnectionStateMachine(.authenticated(nil, [:]))
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "DateStyle", value: "ISO, MDY")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "application_name", value: "")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "server_encoding", value: "UTF8")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "integer_datetimes", value: "on")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "client_encoding", value: "UTF8")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "TimeZone", value: "Etc/UTC")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "is_superuser", value: "on")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "server_version", value: "13.1 (Debian 13.1-1.pgdg100+1)")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "session_authorization", value: "postgres")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "IntervalStyle", value: "postgres")), .wait)
XCTAssertEqual(state.parameterStatusReceived(.init(parameter: "standard_conforming_strings", value: "on")), .wait)
XCTAssertEqual(state.readyForQueryReceived(.idle),
.closeConnectionAndCleanup(.init(action: .close, tasks: [], error: PSQLError.unexpectedBackendMessage(.readyForQuery(.idle)), closePromise: nil)))
}
Again, thanks a lot for driving this forward...
Sources/PostgresNIO/New/Connection State Machine/ConnectionStateMachine.swift
Outdated
Show resolved
Hide resolved
Sources/PostgresNIO/New/Connection State Machine/ConnectionStateMachine.swift
Outdated
Show resolved
Hide resolved
Sources/PostgresNIO/New/Connection State Machine/ConnectionStateMachine.swift
Outdated
Show resolved
Hide resolved
Codecov Report
@@ Coverage Diff @@
## main #296 +/- ##
=======================================
Coverage 43.91% 43.91%
=======================================
Files 115 115
Lines 9678 9680 +2
=======================================
+ Hits 4250 4251 +1
- Misses 5428 5429 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
|
This looks really good now. Only thing left is merge of main into your branch! |
Done! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One Nit remaining...
Sources/PostgresNIO/New/Connection State Machine/ConnectionStateMachine.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome patch @rausnitz! Thanks a ton!
Thanks for the thorough and fast reviews @fabianfett! |
This allows the
ConnectionStateMachine
to be in statereadyForQuery
even if theBackendKeyData
has not been received.The use case that prompted this change is integration with Amazon RDS Proxy. When connecting to Postgres via RDS Proxy, any query fails with error
PSQLError(base: PostgresNIO.PSQLError.Base.unexpectedBackendMessage(.readyForQuery(.idle)))
.According to the RDS Proxy docs, one limitation of RDS Proxy is "For PostgreSQL, RDS Proxy doesn't currently support canceling a query from a client." The Postgres docs explain BackendKeyData's purpose as: "This message provides secret-key data that the frontend must save if it wants to be able to issue cancel requests later. The frontend should not respond to this message, but should continue listening for a ReadyForQuery message."
So, it seems that RDS Proxy for Postgres has no use for BackendKeyData and does not provide it.
Allowing
nil
forBackendKeyData
in this function resolves thePSQLError
error we were seeing.