Nimbusv1.0.0

Smart Scaling Module

Proactive time-based scaling with schedule rules, predictive warmup, and historical player count analysis.

The Smart Scaling module (nimbus-module-scaling) adds proactive, time-based scaling to the Nimbus cloud system. It works alongside the core reactive scaling engine, which handles real-time player demand.

Overview

FeatureCore ScalingEngineSmart Scaling Module
TriggerPlayer count fill rateTime schedules + historical predictions
DirectionScale up + scale downScale up only (never stops servers)
Data sourceLive server pingsDatabase snapshots (7-day history)
Config[group.scaling] in group TOMLconfig/modules/scaling/<Group>.toml

Architecture

Directory Structure
nimbus-module-scaling/
├── SmartScalingModule.kt          # NimbusModule: lifecycle, background loops
├── SmartScalingManager.kt         # Core logic: schedules, predictions, warmup
├── SmartScalingConfig.kt          # TOML config parsing per group
├── SmartScalingTables.kt          # DB tables: snapshots + decisions
├── commands/
│   └── ScalingCommand.kt          # Console + Bridge command
└── routes/
    └── ScalingRoutes.kt           # REST API endpoints

Database tables

smart_scaling_snapshots

Recorded every 60 seconds per dynamic group.

ColumnTypeDescription
idINT (PK)Auto-increment
timestampVARCHAR(30)ISO-8601 instant
group_nameVARCHAR(64)Group name
player_countINTTotal players across ready services
service_countINTNumber of ready services

smart_scaling_decisions

Logged whenever the module starts services.

ColumnTypeDescription
idINT (PK)Auto-increment
timestampVARCHAR(30)ISO-8601 instant
group_nameVARCHAR(64)Group name
actionVARCHAR(32)smart_schedule, smart_warmup, smart_prediction
reasonVARCHAR(512)Human-readable reason
sourceVARCHAR(32)schedule or prediction
services_startedINTNumber of services started

Both tables are auto-pruned after 90 days.

Configuration format

Each group gets a TOML file at config/modules/scaling/<GroupName>.toml:

config/modules/scaling/Lobby.toml
[schedule]
enabled = true
timezone = "Europe/Berlin"

[[schedule.rules]]
name = "evening-peak"
days = ["MON", "TUE", "WED", "THU", "FRI"]
from = "17:00"
to = "23:00"
min_instances = 3
# max_instances = 6    # Optional: cap during this period

[warmup]
enabled = true
lead_time_minutes = 10

Schedule rules

FieldRequiredDescription
nameYesRule identifier (shown in console/API)
daysYesWeekdays: MON, TUE, WED, THU, FRI, SAT, SUN
fromYesStart time (HH:MM, 24h)
toYesEnd time (HH:MM, 24h, overnight ranges like 22:00-02:00 supported)
min_instancesYesMinimum services during this window
max_instancesNoOptional cap (defaults to group's max_instances)

When multiple rules overlap, the one with the highest min_instances wins.

Warmup config

FieldDefaultDescription
enabledtrueEnable predictive warmup
lead_time_minutes10Start servers this many minutes before a schedule activates

Prediction algorithm

The prediction uses a simple historical average:

  1. Load snapshots from the past 7 days
  2. Filter for matching weekday + hour
  3. Calculate average player count
  4. If predicted players exceed current capacity (considering fill threshold), pre-start servers

No machine learning — just a rolling average over same-weekday, same-hour windows.

Events

The module emits ModuleEvent with these types:

Event typeMeaning
SMART_SCHEDULEServices started due to an active schedule rule
SMART_WARMUPServices pre-started for an upcoming schedule
SMART_PREDICTIONServices started based on historical prediction

Console formatters display these with colored output.

ServiceManager access

The module needs ServiceManager to start services, but ServiceManager is created after modules are loaded. The solution uses ModuleContext.registerService():

  1. Core registers ServiceManager after creation: moduleContext.registerService(ServiceManager::class.java, serviceManager)
  2. Module resolves it lazily in its background loop (15s delay): context.service<ServiceManager>()

This pattern is available to any module that needs late-initialized services.

REST API

All endpoints require service-level authentication (default).

MethodEndpointDescription
GET/api/scaling/statusOverview: active schedules, recent decisions
GET/api/scaling/schedulesAll schedule rules for all groups
GET/api/scaling/schedules/{group}Rules for a specific group
GET/api/scaling/history/{group}?hours=24Player count history
GET/api/scaling/predictions/{group}Predictions for next 6 hours
GET/api/scaling/decisions?limit=50Recent scaling decisions

Console commands

Output
scaling status                    # Active schedules + recent decisions
scaling schedule list             # All rules across all groups
scaling history <group> [hours]   # Player history (default 24h)
scaling predict <group>           # Predictions next 6h
scaling reload                    # Reload configs from disk

Per-group rules are exposed via the REST API (GET /api/scaling/schedules/{group}); the console's schedule list already prints every group's rules grouped by group name.

All commands are also available via the Bridge plugin (/cloud scaling ...).