asyncer-io / r2dbc-mysql

Reactive Relational Database Connectivity for MySQL. The official successor to mirromutth/r2dbc-mysql(dev.miku:r2dbc-mysql).
https://r2dbc.io
Apache License 2.0
208 stars 21 forks source link

connection leak when using r2dbc-pool with r2dbc-mysql #294

Open 1528110566 opened 2 hours ago

1528110566 commented 2 hours ago

Environment Windows 11 JDK 1.8.0-381 Spring-parent 2.7.13 r2dbc-mysql 0.9.3

Describe the bug I've been stucked with an bug recently, and I search anywhere on GitHub but nothing. Here is an issue that very close to answer. https://github.com/pgjdbc/r2dbc-postgresql/issues/661 So I wrote an issue under this repo.

It's quit simple. Update something in database transaction, throw an exception if the updated rows is not 1(always true because it's not exists). 2 update statements are triggled by Flux parallel.

Query query = Query.query(Criteria.where("id").is(3));
Update update = Update.update("name", "3");
List<Integer> list = new ArrayList<>();
list.add(0);
list.add(1);
for (int i = 0; i < 1000; i++) {
    Flux.fromIterable(list)
            .flatMap(item -> {
                return transactionalOperator.transactional(template.update(query, update, User.class)
                        .doOnNext(res -> {
                            if (res != 1) {
                                throw new RuntimeException("test");
                            }
                        }));
            })
            .subscribe();
}

The funny thing is, when I change .doOnNext to another block(attention on )), it's works as expected.

Query query = Query.query(Criteria.where("id").is(3));
Update update = Update.update("name", "3");
List<Integer> list = new ArrayList<>();
list.add(0);
list.add(1);
for (int i = 0; i < 1000; i++) {
    Flux.fromIterable(list)
            .flatMap(item -> {
                return transactionalOperator.transactional(template.update(query, update, User.class))
                        .doOnNext(res -> {
                            if (res != 1) {
                                throw new RuntimeException("test");
                            }
                        });
            })
            .subscribe();
}

So, I believe something must not compatible with cancel in reactor and spring-tx. Another thing confusing me is, why the number of r2dbc_pool_acquired_connections always 9.

image image

To Reproduce https://github.com/1528110566/r2dbc-connection-leak-demo This is a demo that can reproduce this bug.

  1. call http://localhost:8080/test
  2. wait background threads are finished
  3. call http://localhost:8080/actuator/prometheus
  4. search r2dbc_pool_acquired_connectionsand r2dbc_pool_idle_connections. We'll find the number of connection in the pool is not as expected. This can be proved with debugging on https://github.com/r2dbc/r2dbc-pool/blob/bf6540eee26aa55bba4cb6ab0c6a3c622524679c/src/main/java/io/r2dbc/pool/ConnectionPool.java#L106. We'will find the number of connection is actually smaller than expected.