Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

LilsDeferred Banner

Persistent command queues and scheduled actions for Paper servers.

Schedule commands for later, queue actions for a player's next login, and keep everything safely persisted across server restarts.

Releases β€’ Modrinth β€’ Issues β€’ MIT License


🌸 What is LilsDeferred?

LilsDeferred is a lightweight utility plugin for Paper that allows server administrators to queue commands and actions to run later.

Tasks can either run after a specified amount of time or the next time a particular player joins the server.

Everything is persisted using SQLite, meaning queued tasks survive restarts and remain available for inspection, cancellation, retrying and historical review.

/deferred in 30m say The event has started!

/deferred player Lily next-login give Lily diamond 3

✨ Features

  • Persistent scheduled console commands
  • Persistent next-login player actions
  • SQLite storage using WAL mode
  • Dedicated asynchronous database executor
  • No recurring SQLite polling for scheduled tasks
  • In-memory priority queue for efficient scheduling
  • Automatic retries for failed scheduled tasks
  • Manual retry support
  • Task cancellation
  • Persistent task history
  • Automatic configurable history cleanup
  • Crash recovery for interrupted tasks
  • Paginated task listings
  • Detailed task inspection
  • Interactive MiniMessage output
  • Clickable Inspect actions in /deferred list
  • Granular permissions
  • Configurable messages
  • Runtime reload support for safe configuration options

⏰ Scheduled Commands

Commands can be scheduled using a simple duration format:

/deferred in <duration> <command...>

For example:

/deferred in 30s say Thirty seconds have passed!

/deferred in 10m broadcast The event begins now!

/deferred in 1h30m say Ninety minutes have passed!

Supported duration units:

Unit Meaning
s Seconds
m Minutes
h Hours
d Days
w Weeks

Units can also be combined:

1h30m
2d12h
1w2d

🌷 Next-Login Actions

Commands can also be queued for the next time a player joins:

/deferred player <player> next-login <command...>

Example:

/deferred player Lily next-login give Lily diamond 3

The task remains stored until that player next connects.

If multiple actions are waiting for the same player, they are executed in creation order.


πŸ“‹ Commands

Command Description
/deferred in <duration> <command...> Schedule a command for later
/deferred player <player> next-login <command...> Queue a command for a player's next login
/deferred list [page] View stored deferred tasks
/deferred inspect <id> Inspect a task in detail
/deferred cancel <id> Cancel a pending or failed task
/deferred retry <id> Retry a failed task
/deferred reload Reload configuration and messages

Task entries shown by /deferred list include a clickable Inspect action for quickly opening the corresponding task.


πŸ” Permissions

Permission Description
lilsdeferred.create Create scheduled and next-login tasks
lilsdeferred.list View stored task listings
lilsdeferred.manage Inspect, cancel and retry tasks
lilsdeferred.reload Reload configuration and messages
lilsdeferred.admin Grants all LilsDeferred permissions

All permissions default to server operators.


πŸ”„ Task Lifecycle

LilsDeferred stores the state of every task explicitly.

PENDING
   β”‚
   β–Ό
RUNNING
   β”‚
   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Ί COMPLETED
   β”‚
   └──────────────► FAILED

Tasks may also transition through:

PENDING ───────────► CANCELLED

FAILED ── retry ──► PENDING

This state-based design also exists at the database level: SQL updates only allow valid transitions such as PENDING β†’ RUNNING or RUNNING β†’ COMPLETED.


πŸ” Retry Behaviour

Failed scheduled tasks can automatically retry according to the configured attempt limit and retry delay.

For example:

execution:
  max-attempts: 3
  retry-delay-seconds: 30

A scheduled task could therefore progress through:

Attempt 1
   ↓
FAILED
   ↓
30 second delay
   ↓
Attempt 2
   ↓
FAILED
   ↓
30 second delay
   ↓
Attempt 3
   ↓
FAILED

Once the maximum attempt count is reached, the task remains FAILED for administrator review.

NEXT_LOGIN tasks are not automatically retried. A failed login action requires manual retry so that its execution remains tied to a future login rather than immediately repeating.


🏑 Architecture

LilsDeferred Architecture

LilsDeferred keeps its runtime, business logic and persistence layers deliberately separated.

Commands / PlayerJoinEvent
          β”‚
          β–Ό
   DeferredTaskService
      β”‚           β”‚
      β–Ό           β–Ό
TaskRepository   ScheduledTaskQueue
      β”‚                 β”‚
      β–Ό                 β–Ό
    SQLite       ScheduledTaskRunner
                          β”‚
                          β–Ό
                     TaskExecutor
                          β”‚
                          β–Ό
                   Paper Main Thread

Responsibilities

DeferredTaskService
Contains task creation, validation, lifecycle, retry and cancellation logic.

TaskRepository
Handles persistent DeferredTask storage and SQL operations.

ScheduledTaskQueue
Maintains scheduled jobs in an in-memory priority queue ordered by execution time.

ScheduledTaskRunner
Checks the in-memory queue for due tasks at a configurable interval.

TaskExecutor
Safely dispatches deferred commands onto Paper's main server thread.


πŸ’Ύ SQLite & Persistence

LilsDeferred uses SQLite for persistent task storage.

The database is configured with:

WAL journal mode
NORMAL synchronous mode
Foreign-key enforcement
Busy timeout protection

A single persistent SQLite connection is owned by a dedicated database executor thread.

Database operations return asynchronous CompletableFuture results and JDBC objects remain contained inside the persistence layer.

Database Migrations

LilsDeferred also uses numbered schema migrations through SQLite's user_version.

This allows future releases to evolve the database schema without requiring users to delete or recreate their existing data.

For example:

Schema 1
   ↓
Migration 2
   ↓
Schema 2
   ↓
Migration 3
   ↓
Schema 3

Older installations automatically apply each required migration in order.


⚑ Performance

LilsDeferred is designed to keep recurring runtime work extremely small.

No Scheduled SQL Polling

A common scheduler design repeatedly performs something like:

SELECT *
FROM deferred_tasks
WHERE execute_after <= ?

every second.

LilsDeferred does not do this.

Instead, pending scheduled tasks are loaded from SQLite at startup and stored in a Java PriorityQueue.

Runtime checks therefore operate against:

PriorityQueue.peek()

rather than repeatedly querying the database.

Dedicated Database Thread

All normal SQLite operations are submitted to a single dedicated executor:

Paper / Command / Event
         β”‚
         β–Ό
   Database Job Queue
         β”‚
         β–Ό
LilsDeferred-Database
         β”‚
         β–Ό
       SQLite

No normal database query is intentionally performed synchronously on Paper's main thread.

Indexed Queries

Indexes are maintained for the queries that benefit from them, including:

  • pending scheduled task loading
  • next-login player lookups
  • historical task cleanup
  • task listing order

Backlog Protection

If a server has been offline for a long period and many scheduled tasks become overdue, LilsDeferred does not attempt to submit the entire backlog in one queue check.

execution:
  max-tasks-per-check: 100

Remaining tasks are processed over later checks.


πŸ›‘οΈ Crash Safety

There is an unavoidable ambiguity when executing persistent commands:

Task marked RUNNING
        ↓
Command dispatched successfully
        ↓
Server crashes
        ↓
COMPLETED state was never persisted

Automatically replaying that command could duplicate something important such as:

  • item rewards
  • economy payments
  • permissions
  • crate keys
  • administrative actions

For this reason, tasks found in the RUNNING state during startup are not automatically executed again.

Instead, LilsDeferred marks them:

FAILED

with an explanation that their previous execution outcome is unknown.

An administrator can then inspect the task and manually retry it if appropriate.


🧹 History Cleanup

Completed and cancelled task history can be automatically removed after a configurable number of days.

history:
  retention-days: 30

The cleanup system only removes old:

COMPLETED
CANCELLED

tasks.

It never automatically removes:

PENDING
RUNNING
FAILED

tasks.

Set the retention period to:

retention-days: 0

to keep historical tasks indefinitely.

Cleanup runs periodically and the actual deletion is performed asynchronously by the database executor.


βš™οΈ Configuration

LilsDeferred ships with a fully commented config.yml.

Main settings include:

database:
  file: "deferred.db"
  busy-timeout-ms: 5000

execution:
  check-interval-ticks: 20
  max-tasks-per-check: 100
  max-attempts: 3
  retry-delay-seconds: 30

history:
  retention-days: 30

Reloadable Settings

The following values are applied by:

/deferred reload
  • execution.max-attempts
  • execution.retry-delay-seconds
  • history.retention-days
  • messages.yml

Restart-Required Settings

These settings configure components that are created during plugin startup and therefore require a restart:

  • database.file
  • database.busy-timeout-ms
  • execution.check-interval-ticks
  • execution.max-tasks-per-check

🎨 Messages

Player and administrator-facing messages are stored separately in:

messages.yml

LilsDeferred uses Adventure MiniMessage, allowing server owners to customise:

  • colours
  • gradients
  • hover text
  • clickable actions
  • formatting

without modifying the plugin.


πŸ“¦ Installation

  1. Download the latest LilsDeferred release.
  2. Place the .jar file into your server's plugins/ directory.
  3. Start or restart the server.
  4. Configure config.yml and messages.yml as desired.
  5. Use /deferred to begin creating tasks.

LilsDeferred automatically creates and migrates its SQLite database when required.


βœ… Requirements

  • Paper 26.2+
  • Java 25

LilsDeferred is developed and tested against Paper.

Other server implementations are not currently officially supported.


πŸ› οΈ Building from Source

Clone the repository:

git clone https://github.com/LilyK-97/LilsDeferred.git
cd LilsDeferred

Build using the included Gradle Wrapper.

Windows

.\gradlew clean build

Linux / macOS

./gradlew clean build

The resulting plugin will be available in:

build/libs/

🌸 The Lils Plugin Collection

LilsDeferred is part of the Lils collection: a growing set of clean, lightweight Paper utilities with a focus on practical server administration, efficient implementation and maintainable code.

The goal of each project is to remain focused rather than becoming an oversized all-in-one plugin.


🀝 Issues & Contributions

Bug reports, suggestions and contributions are welcome.

When reporting a bug, please include relevant server logs, your Paper version and steps to reproduce the issue where possible.


πŸ”— Links


πŸ“œ License

LilsDeferred is open-source software licensed under the MIT License.

You are free to use, modify and redistribute the project in accordance with the terms of the license.

See the full LICENSE file for details.


Made with 🌸Love🌸 for Paper servers.

About

Persistent command queues and scheduled actions for Paper servers.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages