Skip to content

[Bug]: Player balances lost on shutdown onDisable() cancels coroutine scope and closes DB before syncAccounts() completes #130

Description

@VitzS7

What happened?

On a graceful server shutdown (scheduled restart via Bukkit.shutdown(), so onDisable() DOES run), player balances that were only in the in-memory cache are lost. After the restart the balance reverts to the last value that had actually reached the database.

Concrete case on my server:

  • A player's balance rose to ~21,646 at 22:34 and stayed there for over an hour.
  • At 00:00 a scheduled restart ran (graceful — onDisable executed for every plugin).
  • After reboot the balance was back to ~1,646 (≈20,000 lost). The transaction was present in the monolog, but the cached balance never reached the DB.

Root cause is a race condition in onDisable(). From the current source (com/github/encryptsl/lite/eco/LiteEco.kt):

override fun onDisable() {
    schedulerHelper.cancelTasks()
    hookManager.unregisterHooks()
    api.syncAccounts()          // launches the save asynchronously (coroutines) — does NOT wait
    pluginScope.cancel()        // cancels the scope that just received the work
    databaseConnector.onDisable() // closes the DB connection
    logger.info("Plugin is disabled")
}

syncAccounts() dispatches the flush on a coroutine and is not awaited. The very next lines cancel pluginScope and close the Hikari pool, so the pending writes are cancelled / hit a closed datasource before they commit. There is no runBlocking / join() guaranteeing the sync finishes before the scope and connection are torn down.

The shutdown log confirms it: the whole LiteEco onDisable happens within the SAME second, and there is no "synchronizing N accounts" / "saved" line before "Database connection closed cleanly":

[00:00:02] [LiteEco] Disabling LiteEco v1.7.4-SNAPSHOT
[00:00:02] [LiteEco] Unregistering hooks...
[00:00:02] [HikariDataSource] LiteEco - Shutdown initiated...
[00:00:02] [HikariDataSource] LiteEco - Shutdown completed.
[00:00:02] [LiteEco] ✅ Database connection closed cleanly.
[00:00:02] [LiteEco] Plugin is disabled

Expected: onDisable() must block until syncAccounts() actually finishes committing (e.g. runBlocking { ... } / awaiting the sync job) BEFORE cancelling pluginScope and closing the database connection, so no cached balance is lost on shutdown.

Secondary observation (may be related): during the session the janitor synced Bedrock/Floodgate UUIDs frequently, but the affected player's online Java UUID was only synced once (at the moment he disconnected) and never again while online — so the gain stayed cache-only until the broken shutdown dropped it.

Plugin Version

1.7.4-SNAPSHOT

You detected problem on this server platform ?

PaperMC

Version /version - output

This server is running Leaf version 1.21.11-147-ver/1.21.11@d2c6e0a (2026-05-22T06:26:23Z) (Implementing API version 1.21.11-R0.1-SNAPSHOT)
* You are 21 version(s) behind
Download the new version at: https://www.leafmc.one/download

Relevant log output

[16:30:46] [Server thread/INFO]: [LiteEco] Loading server plugin LiteEco v1.7.4-SNAPSHOT
[16:31:04] [DefaultDispatcher-worker-1/INFO]: [LiteEco] New version available [1.7.5-SNAPSHOT], you are using [1.7.4-SNAPSHOT]

--- graceful scheduled shutdown at 00:00 (onDisable ran, but no sync confirmation before the DB closed) ---
[00:00:02] [Server thread/INFO]: [LiteEco] Disabling LiteEco v1.7.4-SNAPSHOT
[00:00:02] [Server thread/INFO]: [PlaceholderAPI] Unregistered placeholder expansion liteeco
[00:00:02] [Server thread/INFO]: [PlaceholderAPI] Reason: required plugin LiteEco was disabled.
[00:00:02] [Server thread/INFO]: [LiteEco] Unregistering hooks...
[00:00:02] [Server thread/INFO]: [com.zaxxer.hikari.HikariDataSource] LiteEco - Shutdown initiated...
[00:00:02] [Server thread/INFO]: [com.zaxxer.hikari.HikariDataSource] LiteEco - Shutdown completed.
[00:00:02] [Server thread/INFO]: [LiteEco] ✅ Database connection closed cleanly.
[00:00:02] [Server thread/INFO]: [LiteEco] Plugin is disabled

Metadata

Metadata

Assignees

Labels

BugSomething no workingNotFixedThis bug not fixed

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions