Releases: vinicius-paraujo/Pillar
Release list
v0.6.2 — Redis Reliability & Command Fixes
Patch release focused on Redis connection reliability, command behavior, and operational visibility.
Fixed
- Redis driver failures now retain and log their original cause, with throttling and suppressed-event counts.
- Blocking inbox reads now have a client-side deadline, preventing consumers from remaining parked indefinitely on dead connections.
- Redis health now requires three consecutive probe failures before entering degraded mode, preventing brief stalls from disabling the control plane.
/pillartab completion is registered correctly on Paper./pillar reload <role>reports successful and failed node counts instead of displaying a literal<count>./pillar reloadsuggests roles represented by servers currently online.- Receiving nodes log who requested a reload and whether it succeeded or failed.
- Plugin descriptors report the correct version.
- Maven Central metadata points to the correct GitHub repository.
- The Gradle wrapper is executable on Linux and macOS.
Changed
- Gson is now an explicit dependency instead of arriving transitively through Jedis.
- CI now builds and tests the project on every push and pull request, rejecting skipped tests in the release environment.
No breaking public API changes. Requirements remain Java 25, Redis 7, and a supported Paper and/or Velocity platform.
v0.6.1 — Minor fixes
Patch release. Fixes a login-time crash uncovered during Velocity 4.0.0 compatibility testing.
Fixed
- Empty
routing.entry-rolecrashed every login attempt (ServerRole must not be blank) instead of skipping Pillar's routing, despite the config file's own comment documenting that exact behavior.
No public API changes. pillar-api on Maven Central stays at 0.6.0.
Pillar v0.6.0 — Documentation, Module Split & Maven Central
Pillar v0.6.0 — Documentation, Module Split & Maven Central
Iteration 6 completes the public documentation and prepares the codebase for community adoption by strictly separating the API contracts from the implementation. It enforces a hard physical boundary, ensuring pure API contracts with zero external dependencies, and officially publishes the artifact to Maven Central for direct consumer consumption.
Architecture & Distribution
- Module Split — Enforced a hard architectural boundary via Gradle. The project is now separated into two physical subprojects:
pillar-apicontaining pure Java API contracts (with no external dependencies other than the JDK), andpillar-pluginhousing the implementations, shading, and platform adapters. - Maven Central Publication — The
pillar-apiartifact is now formally published to Maven Central. Plugin developers can now securely depend on the API contracts using standard dependency managers (Gradle/Maven) without relying on custom repository definitions.
Documentation & Community
- Public Documentation — Launched an extensive documentation site at pillar.markineo.com.br, built with Starlight. It features comprehensive architecture overviews, detailed developer cookbooks, and a structured getting-started guide.
- Internationalization (i18n) — Full documentation support established for English (EN), Spanish (ES), and Brazilian Portuguese (PT-BR), heavily audited to ensure native software engineering taxonomy across all supported languages.
API Hardening
- Lease API Minimization — Reduced the public surface area of the
LeaseServiceby explicitly removingOwnerTokenexposures from theLeaserecord. The fencing token is now handled implicitly by internal systems, relying entirely on atomic Redis Lua script fencing to guarantee absolute safety without leaking implementation details to consumers.
Upgrading from 0.5.0
Drop-in replacement for server administrators. No breaking configuration changes. Requirements remain unchanged: Paper 26.1.2 and/or Velocity 3.4.0, Java 25, Redis 7.
Plugin developers must update their build scripts to depend on the newly published pillar-api artifact from Maven Central, utilizing compileOnly (Gradle) or the provided scope (Maven).
What's next (Iteration 7 — Marketing & Outreach)
Iteration 7 will focus on launch and community adoption, targeting small and medium networks. Work will encompass publishing the plugin to major platforms (Modrinth, Hangar, SpigotMC, Polymart) and executing a structured, culturally adapted outreach strategy across the pt-BR, EN, and ES communities.
Pillar v0.5.0 — The Messaging API & Documentation Consolidation
Pillar v0.5.0 — The Messaging API & Javadoc Consolidation
Iteration 5 extracts the internal core capabilities into a stable, public-facing API surface. It transforms Pillar from a closed routing proxy into an extensible platform, providing developers with type-safe distributed primitives for cross-server communication, mutual exclusion, and direct routing control, backed by exhaustive concurrency contracts.
Public API Surface & Distributed Primitives
Messaging API — Introduced a complete messaging suite (Pillar#messaging) backed by Redis Streams. Developers can now utilize one-way Pub/Sub (listen/send), asynchronous Request-Response with explicit timeouts (sendRequest), and universal network broadcast, entirely abstracted from the underlying transport layer.
Leases API — Introduced a distributed lock mechanism (Pillar#leases) for mutual exclusion across the fleet. Backend servers can now safely acquire exclusive leases over logical resources (e.g., preventing two lobbies from simultaneously booting the same minigame state).
Routing API — Exposed backend-driven actuation (Pillar#routing), allowing Paper servers to command the proxy to move players. Supports both direct routing (moveToServer) and role-based placement (moveToRole) using the same proxy-side P2C load-balancing algorithm.
API Hardening & Thread-Safety Contracts
Main-Thread Enforcement — Explicitly locked down CompletableFuture contracts. API futures always complete on internal Pillar dispatch threads. Calling join() or get() from the platform's main thread now throws an immediate IllegalStateException, forcibly preventing developers from introducing blocking operations that freeze the server.
Thread-Hopping Abstractions — Introduced MessageContext#sync for deterministic execution. It abstracts platform-specific threading guarantees: scheduling on the next tick for Paper when off-thread, while running inline to lock the worker pool on Velocity.
Records & Sum Types — Redesigned message payloads and routing outcomes to heavily utilize Java 21+ records and sealed interfaces, ensuring immutability and complete type-safety across the distributed boundary.
Upgrading from 0.4.0
Drop-in replacement. No breaking configuration changes. Requirements remain unchanged: Paper 26.1.2 and/or Velocity 3.4.0, Java 25, Redis 7. Plugin developers should migrate from internal classes to the new br.com.markineo.pillar.api package.
What's next (Iteration 6 — Maven Publication)
Iteration 6 will focus on decoupling the pillar-api module for public Maven publication via build.gradle and rebuilding the official documentation site to guide developers on utilizing the new distributed primitives.
Pillar v0.4.0 — Production Hardening & Resilience
Pillar v0.4.0 — Production Hardening & Resilience
Iteration 4 closes the reliability gap. It transforms the system from a functioning MVP into a fault-tolerant mesh that degrades gracefully under fire. We've introduced explicit degraded modes, a self-healing background garbage collector for abandoned state, and local-first telemetry.
Telemetry & Diagnostics
- /pillar doctor command — New administrative subcommand exposing typed decision telemetry and anomaly-focused health checks. Built with a strictly local-first philosophy (zero-cost
AtomicLongcounters and ring buffers), it ensures diagnostic availability even when Redis is down.
Self-Healing & Resilience
- Orphan-inbox reaping — The proxy now runs a self-healing background service (
InboxReaper) that safely reaps abandoned inboxes and dead-letters from permanently dead nodes. It uses atomic Lua scripts (EXISTS+DEL) to prevent memory leaks over time. - Degraded modes — Introduced read-outcome-driven stale retention with bounded windows. Nodes now automatically fall back to their last-known-good state during transient Redis outages, explicitly documenting their degraded contracts rather than failing blindly.
Targeted Operations
- Targeted reloads — Added
/pillar reload <role>to allow signal-onlyRELOAD_CONFIGfan-out to specific server roles, replacing cluster-wide config blasts and reducing unnecessary I/O.
Internal Quality & Hot-path Optimizations
- Zero-allocation Routing — Refactored
DecisionBuffer(placement history) into a lock-free, zero-allocation Ring Buffer usingAtomicReferenceArray. - Sum Types — Rewrote
PlacementDecisiontypes using Java 21+ sealed interfaces and records, eliminatingOptionalheap allocation overheads in critical loops. - Failure Drills — Added automated Testcontainers assertions locking the degraded-mode contract and orphan reaping mechanisms, ensuring these resilience features are immune to future regressions.
Upgrading from 0.3.0
Drop-in replacement. No breaking configuration changes. Requirements remain unchanged: Paper 26.1.2 and/or Velocity 3.4.0, Java 25, Redis 7.
What's next (Iteration 5 — Public API Surface)
Iteration 5 will focus on extracting the stable public surface into a pillar-api module and enforcing strict package boundaries with ArchUnit tests, preparing the system for external adoption and the public documentation site (Iteration 6).
Pillar v0.3.0 — The Control Plane Acts
v0.3.0 — The Control Plane Acts
Iteration 1 taught Pillar to see the fleet. Iteration 2 taught it to decide. This release teaches it to act: players are placed, moved, messaged, and resources are locked — all through the existing envelope machinery, with zero Redis I/O on the login hot path.
Highlights
Player routing at login
Joining players are placed on the configured entry role via the Iteration 2 placement engine (eligibility hard caps → P2C selection → in-flight reservation). The entire decision reads three in-memory volatile snapshots and touches Redis zero times. When no node is eligible, the connection is refused with a localizable message.
Cross-server player movement
Any game server can request Pillar to move a player to a specific server or to a role (placement decides the best node). The proxy actuates the connection and reports the outcome back to the requester: SUCCESS, NO_ELIGIBLE_NODE, PLAYER_OFFLINE, UNKNOWN_TARGET, or CONNECTION_FAILED.
Player and network messaging
SEND_PLAYER_MESSAGE delivers a MiniMessage component to a named player wherever they are on the network. BROADCAST delivers to every connected player. The proxy resolves targets; the sender never needs to know which server a player is on.
Generic lease primitive
LeaseService.acquire(resource, owner, ttl) provides mutual exclusion across the fleet via atomic SET NX PX + owner-checked Lua renew/release. SkyBlock islands, minigame arenas, unique bosses — any resource that needs exactly one owner. No Redlock; guarantee boundary documented in ADR-0008.
In-memory health cache
HealthRegistry refreshes a volatile snapshot of the fleet's health on a background loop, powering the zero-I/O login path and the automatic least-connections fallback when telemetry degrades.
withResource consolidation
RedisConnector.withResource(fn) replaces duplicated getResource + exception handling across all Redis adapters, sealing the raw JedisPool inside the lifecycle package.
End of this release = MVP (FR-01 through FR-07).
What's next
Iteration 4 — Production Hardening: pending-message recovery from dead consumers (XAUTOCLAIM), defined degraded-mode behavior and self-recovery, /pillar doctor with decision telemetry and placement explanations, and failure drill scripts.
Pillar v0.2.0 — The Decision Engine
0.1.0 taught the fleet to see each other and pass messages. 0.2.0 teaches it
to decide: nodes now publish their own health, and Pillar chooses where work
should land — filtering on hard caps, then balancing with power-of-two-choices
over an in-memory view. The reliability tier underneath grew up too.
Pre-release — the placement logic is complete and tested, but not yet wired
to player routing. That actuation lands in Iteration 3 (the MVP line).
Health & placement
- Health snapshots — each node publishes MSPT, memory, player/world counts, and pending-signal depth, TTL-bounded and self-healing like presence; any node reads the fleet's latest health.
- Eligibility (hard caps) — a node over its player, MSPT, or memory ceiling is filtered out before any optimization runs.
- Power-of-two-choices — samples two eligible nodes and keeps the lighter, over an in-memory snapshot: O(1), with no herd toward a single "best" node.
- In-flight reservations — TTL'd and counted into scoring, so a burst of concurrent placements spreads across the fleet instead of stampeding one node.
- Least-connections fallback — when health data is stale or absent, selection degrades automatically instead of routing blind.
- Simulation harness — synthetic bursts against a fleet larger than the real 2-node topology prove even distribution and cap adherence at volume.
Reliable dispatch
- Bounded worker pool — handlers run off the consumer thread; a saturated pool blocks the consumer, so backpressure is natural rather than dropped work.
- Ack-after-success —
XACKonly after a handler completes; failures stay pending. - PEL reclaim + dead-lettering — orphaned entries (e.g. after
kill -9) are drained and retried on restart, and dead-lettered after N attempts, so nothing accumulates unbounded. - At-least-once dedup — a redelivered entry is recognized and never re-executed; the dedup window is TTL-bounded.
Hardening
- Redis package split into
presence/transport/lifecyclefor clearer boundaries. - Fleet reads (
/pillar fleet, ping presence, tab-completion) served from an in-memory snapshot — noSCAN+MGETon a platform thread. JedisPoolsized explicitly (config-driven), replacing the library defaults that starve under login bursts and block callers forever.
Upgrading from 0.1.0
Drop-in. Two new optional keys under redis.pool (max-total, max-wait-millis) with safe defaults — set them only when tuning for load. No breaking config changes. Requirements unchanged: Paper 26.1.2 and/or Velocity 3.4.0, Java 25, Redis 7.
Known limitations
- Placement is decision-only here — the selector is not yet connected to player connections. It ships as pure, tested logic; the wiring and the typed no-eligible-node outcome land in Iteration 3 with its first real consumer.
- Cross-consumer PEL recovery — reclaiming a dead peer's pending entries (
XAUTOCLAIM) — is still pending; only a node's own orphans are reclaimed. - Carried from 0.1.0: dispatch-level self-send misroute; extracted
lang/files can shadow newer keys.
What's next (Iteration 3 — MVP)
Actuation. Player routing wires this engine to the Velocity connect event, reading health from an in-memory cache so the login path never touches Redis; a generic lease primitive (resource → owner, TTL, renewal) gives consumers atomic cross-server exclusivity; and player messaging completes FR-05. End of Iteration 3 = the MVP — a control plane that both decides and acts.
Pillar v0.1.0 — First light
Pre-release. Pillar is in early, iterative development. The public surface is
unstable (0.x) and this build is for validation, not production. See Known limitations.
Pillar is the control plane of the network — it knows the fleet and carries
cross-server messages. This first release lays the communication foundation that later
iterations build routing and health decisions on. A single artifact runs on both Paper
(game servers) and Velocity (proxies).
Highlights
- Fleet presence — nodes announce themselves via expiring heartbeat keys; a dead
node drops from every view within ~9 s through native Redis TTL. No central registry. - Stream transport — JSON envelopes over Redis Streams, one consumer group per
node, with poison-entry drop and handler-failure isolation. - Correlated request/response — non-blocking
CompletableFutureAPI with scheduled
timeouts; results hop back to the main thread safely. - Diagnostics —
/pillar fleet,/pillar status(connection, pending inbox,
recent log),/pillar ping <server>,/pillar reload. Localized (en-us, pt-br).
Requirements
- Paper 26.1.2 and/or Velocity 3.4.0
- Java 25
- A reachable Redis 7 instance
Install
- Drop
Pillar-0.1.0.jarinto each server's and the proxy'splugins/folder. - Start once to generate
config.yml/config-velocity.yml; set the node name,
role, and Redis connection. - Restart. Verify with
/pillar fleet.
A ready-made local topology (proxy + 2 Paper nodes + Redis) lives in test-topology/.
Known limitations
- Messages delivered but unacknowledged when a JVM is killed (
kill -9) stay pending
until PEL reclaim lands (planned). - A node pinging itself is misrouted (self-send); use
pingbetween distinct nodes. - Message handling is single-threaded per node — fine for this release's light traffic,
being reworked before heavier handlers arrive. - Extracted
lang/files are not overwritten on update; delete them to pick up new keys.
What's next (Iteration 2)
Health snapshots (MSPT/memory/players) and placement/routing decisions over them.