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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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