r2dbc / r2dbc-pool

Connection Pooling for Reactive Relational Database Connectivity
https://r2dbc.io
Apache License 2.0
331 stars 55 forks source link

Unable to customize the password when creating the connection #173

Closed mnbattaglia closed 2 years ago

mnbattaglia commented 2 years ago

We are using AWS RDS IAM to get a temporary access token that must be used as the connection password. This is valid only for 15 min, so we must obtain another token when creating a new connection. By using a connection pool, the solution is to set a max life time with a less than 15 min duration (eg: 14 min) and connection should be re-created after that. There are several solutions in the web with JDBC implementations, where you can implement your own pool (eg: extending Hikari) and then overwrite the getPassword function, calling the proper AWS method to get the token at that moment. I'm trying a similar approach with r2dbc, but cannot get to hook while creating the connection. I'm using spring boot. Tried:

In summary, what I'm trying to achieve is to set the password dynamically when connection is being created in the pool. Any suggestions? Thanks in advance

mnbattaglia commented 2 years ago

Closing this one as it was properly answered in an r2dbc-postgres issue

The following example provided by @mp911de works like a charm:

ConnectionFactoryOptions options = ConnectionFactoryOptions.parse("r2dbc:postgresql://host/database");

ConnectionFactory connectionFactoryStub = ConnectionFactories.get(options);

Mono<? extends Connection> connectionPublisher = Mono.defer(() -> {

    ConnectionFactoryOptions optionsToUse = options.mutate()
        .option(ConnectionFactoryOptions.USER, "…") // provide a new username each time we see a connect request
        .option(ConnectionFactoryOptions.PASSWORD, "…") // provide a new password each time we see a connect request
        .build();

    return Mono.from(ConnectionFactories.get(optionsToUse).create());
});

ConnectionFactory myCustomConnectionFactory = new ConnectionFactory() {

    @Override
    public Publisher<? extends Connection> create() {
        return connectionPublisher;
    }

    @Override
    public ConnectionFactoryMetadata getMetadata() {
        return connectionFactoryStub.getMetadata();
    }
};

ConnectionPoolConfiguration poolConfiguration = ConnectionPoolConfiguration.builder().connectionFactory(myCustomConnectionFactory).build();
ConnectionPool pool = new ConnectionPool(poolConfiguration);
// …

My mistake was that I was not deferring the create() delegate