Skip to content
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

connection leak with hikari and multithreading #421

Closed
hafarooki opened this issue Nov 4, 2018 · 13 comments
Closed

connection leak with hikari and multithreading #421

hafarooki opened this issue Nov 4, 2018 · 13 comments

Comments

@hafarooki
Copy link

hafarooki commented Nov 4, 2018

I'm not 100% sure what the cause is here. It seems to be leaking connections through simple transactions.

First, Hikari warns about it: https://gist.github.com/Miclebrick/2771678343cea9cf5be56990a0ab9077

Then anything trying to access the database times out: https://gist.github.com/Miclebrick/401c91dfbddca4b7cdbdf88d9dd76b5c

I'm not really sure where the problem lies on this one.

        transaction {
            val updated: Int = SLPlayers.update({ SLPlayers.id eq uuid }) {
                it[this.lastKnownName] = name
                it[this.lastSeen] = System.currentTimeMillis()
            }

            if (updated == 0) SLPlayers.insert {
                it[this.id] = EntityID(uuid, SLPlayers)
                it[this.lastKnownName] = name
                it[this.lastSeen] = System.currentTimeMillis()
            }
        }

that's where the connection leak warning is triggered (also, does exposed let you update if present else insert somehow? I did it that way as a workaround when I first started using it.)

@Tapac
Copy link
Contributor

Tapac commented Nov 4, 2018

What database do you use? Do you have concurrent requests or that issue happens in a single thread?

Check this part of FAQ about upsert.

@hafarooki
Copy link
Author

I'm using MySQL, the database stuff happens concurrently so as to not block the main game thread. I figured it'd be thread-safe using Hikari as a data source?

Thanks for the link to the upsert page

@hafarooki
Copy link
Author

hafarooki commented Nov 4, 2018

it might not actually be an application level issue, because it happens in multiple application instances at the same time, but other (non-Exposed) applications using the database with Hikari are fine for some reason.

@hafarooki
Copy link
Author

https://gist.github.com/Miclebrick/c6ecd93d3b192de3e4507b691f384344 I made a system to report the stack trace of thread stuck on database calls, here is one (it's another upsert-lack workaround, I wonder if that's related?)

@hafarooki
Copy link
Author

https://gist.github.com/Miclebrick/3bbe765035ed96b0d969d13fc523fca9 Hikari is also warning of a connection leak on startup now

@hafarooki
Copy link
Author

https://gist.github.com/Miclebrick/e9b2770722107872ea7c0c070c15b8ad once again it happened, except this time, it was using this upsert method: #167 (comment)

seems to consistently be either upserts or upsert workarounds? Maybe a coincidence but that's what it is so far

@hafarooki
Copy link
Author

brettwooldridge/HikariCP#754 after reading this I think it may be a bug with the mysql connector, I'm going to try mariadb instead

@hafarooki
Copy link
Author

It still happens with the mariadb driver: https://gist.github.com/Miclebrick/634d384a82d34bdd48f3d12b8f9386b4 but it's still waiting on sockerRead0

@Tapac
Copy link
Contributor

Tapac commented Nov 7, 2018

I would advise to connect to MySQL directly (with CLI or some client) and execute SHOW PROCESSLIST and SHOW ENGINE INNODB STATUS. Output could give you some clue on what's happened on a database side.

@hafarooki
Copy link
Author

hafarooki commented Nov 7, 2018

Could I automate that by opening a new connection without Hikari and doing transaction(tempDatabase) { exec("SHOW ENGINE INNODB STATUS") }?

@Tapac
Copy link
Contributor

Tapac commented Nov 7, 2018

I think you can, but I'd prefer to use some tool where you can easily copy output from. You can take free MySQL Workbench for example.

@hafarooki
Copy link
Author

I made it automatically do it in case it happens when I'm not present like this:

                        val tmpDb = Database.connect(/* ... */)

                        transaction(tmpDb) {
                            exec("SHOW PROCESSLIST") { processList ->
                                val file = File(plugin.dataFolder, "processListDump.txt")
                                Files.write(file.toPath(), processList.toStrings())
                                log.info("Dumped process list to ${file.path}")
                            }

                            exec("SHOW ENGINE INNODB STATUS") { innoDbStatus ->
                                val file = File(plugin.dataFolder, "innoDbStatusDump.txt")
                                Files.write(file.toPath(), innoDbStatus.toStrings())
                                log.info("Dumped innodb status to ${file.path}")
                            }
                        }

tested it with thread.sleep

@hafarooki
Copy link
Author

hafarooki commented Nov 29, 2018

I "fixed" this by making a method for synchronized transactions, which locks on a file so that multiple application instances can't insert concurrently to mess it up. I guess this means this is not an Exposed issue, though, it's just an issue with concurrent inserting and my inability to deal with it properly, so I'll close this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants