-
Notifications
You must be signed in to change notification settings - Fork 289
Pool Postgres connections #3043
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
7dca161 to
9f9bdce
Compare
7cfa3c2 to
edc36eb
Compare
|
See #3030 for local performance characteristics. |
|
There are now conformance tests for Postgres which will make it easier to regression-test this, but the conformance test PR is probably blocked on the data types PR, which is probably blocked on the conformance test PR. It would be good to get some reviews on this little knot of PRs and figure out how to land them. |
| async fn build_client(address: &str) -> Result<Self> | ||
| where | ||
| Self: Sized; | ||
| pub trait ClientFactory: Send + Sync { |
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.
🏭
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.
I think it should be safe to add + 'static here, which would let us remove all the related Send + Sync + 'static constraints elsewhere.
crates/factor-outbound-pg/src/lib.rs
Outdated
| type RuntimeConfig = (); | ||
| type AppState = (); | ||
| type InstanceBuilder = InstanceState<C>; | ||
| type AppState = Arc<RwLock<CF>>; |
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.
I'd recommend leaving interior mutability up to the trait implementation if possible; some implementations might not need to lock.
| type AppState = Arc<RwLock<CF>>; | |
| type AppState = Arc<CF>; |
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 would require changing the trait to use immutable borrows which is fine, but it will complicate the implementation of the ClientFactory.
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.
I have deleted several stream-of-consciousness comments about this to summarize here:
There is a performance hazard with the current impl: this lock is held for the duration of the async call to ClientFactory::build_client. If that async call doesn't complete immediately then calls to open_connection from other instances (of the same app) will be blocked.
I don't know how much this problem would apply to PooledTokioClientFactory; that would depend on the runtime behavior of Pool::get.
Pushing interior mutability down into the ClientFactory won't fix this on its own but it would allow a fancier impl like using a read lock to check for the entry before falling back to the write lock. Or using moka.
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.
moka worked really nicely. Thanks for the pointer!
| async fn build_client(address: &str) -> Result<Self> | ||
| where | ||
| Self: Sized; | ||
| pub trait ClientFactory: Send + Sync { |
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.
I know it didn't have doc comments before, but it would be awesome if it gained some.
crates/factor-outbound-pg/src/lib.rs
Outdated
| type RuntimeConfig = (); | ||
| type AppState = (); | ||
| type InstanceBuilder = InstanceState<C>; | ||
| type AppState = Arc<RwLock<CF>>; |
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 would require changing the trait to use immutable borrows which is fine, but it will complicate the implementation of the ClientFactory.
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
edc36eb to
d951aae
Compare
| impl Default for PooledTokioClientFactory { | ||
| fn default() -> Self { | ||
| Self { | ||
| pools: moka::sync::Cache::new(CONNECTION_POOL_CACHE_CAPACITY), |
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.
@lann I'd value your input on whether we need to provide a way for hosts (e.g. multi-tenant environments) to configure cache (and pool) sizes and policies (e.g. idle time eviction). But also happy to punt that to a separate PR if that's not yet obvious.
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.
I think punting on configurability is fine.
|
|
||
| impl<C: Send + Sync + Client> spin_world::spin::postgres::postgres::HostConnection | ||
| for InstanceState<C> | ||
| impl<CF: ClientFactory + Send + Sync> spin_world::spin::postgres::postgres::HostConnection |
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.
nit: Some redundant generic constraints remain in this file.
| /// Max connections in a given address' connection pool | ||
| const CONNECTION_POOL_SIZE: usize = 64; | ||
| /// Max addresses for which to keep pools in cache. | ||
| const CONNECTION_POOL_CACHE_CAPACITY: u64 = 1024; |
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.
I think we should start with a smaller number here. I think its more likely for a large number of idle connections to cause problems than for someone to actually want this many connections open for one app, and you'd almost certainly want this to be configurable at that point anyway.
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.
Picking a differently arbitrary number... 16?
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
d951aae to
58b68da
Compare
Fixes #3030.
Draft for now. Needs more testing and some tidying but I want to see if tests pass, and to verify with factors experts if I have the pools in the right place (AppState).