sql setup

This commit is contained in:
2026-05-26 00:47:01 -04:00
parent 981d26d003
commit 5714bec389
10 changed files with 325 additions and 0 deletions
+32
View File
@@ -32,6 +32,20 @@
},
"rpc": {
"timeout_ms": 5000
},
"mysql": {
"enabled": false,
"host": "127.0.0.1",
"port": 3306,
"database": "kweebec",
"user": "kweebec",
"password": null,
"max_pool_size": 10,
"min_idle": 2,
"connection_timeout_ms": 5000,
"idle_timeout_ms": 600000,
"max_lifetime_ms": 1800000,
"use_ssl": false
}
}
```
@@ -78,6 +92,23 @@
|---|---|---|
| `timeout_ms` | `5000` | How long an RPC request waits for a response before completing the future exceptionally with `TimeoutException`. |
### mysql
| Field | Default | Meaning |
|---|---|---|
| `enabled` | `false` | Master switch. When false, `getDatabase()` returns null and no pool is created. Set to true once you've put real credentials in place. |
| `host` | `"127.0.0.1"` | MySQL host. |
| `port` | `3306` | MySQL port. |
| `database` | `"kweebec"` | Database (schema) name. Must exist before NetworkCore boots; we don't auto-create databases. |
| `user` | `"kweebec"` | MySQL user. |
| `password` | `null` | MySQL password. Prefer the env var. |
| `max_pool_size` | `10` | Hikari `maximumPoolSize`. |
| `min_idle` | `2` | Hikari `minimumIdle`. |
| `connection_timeout_ms` | `5000` | Hikari `connectionTimeout`. |
| `idle_timeout_ms` | `600000` (10 min) | Hikari `idleTimeout`. |
| `max_lifetime_ms` | `1800000` (30 min) | Hikari `maxLifetime`. Keep below MySQL's `wait_timeout`. |
| `use_ssl` | `false` | Adds `useSSL=true` to the JDBC URL. Turn on whenever MySQL is on a different host than the Hytale server. |
## Environment variable overrides
These take precedence over the config file at boot time. Use them for secrets so the config file stays safe to check into version control.
@@ -86,6 +117,7 @@ These take precedence over the config file at boot time. Use them for secrets so
|---|---|
| `REDIS_PASSWORD` | `redis.password` |
| `NETWORK_AUTH_TOKEN` | `network.auth_token` |
| `MYSQL_PASSWORD` | `mysql.password` |
## Recommended setup per environment
+100
View File
@@ -0,0 +1,100 @@
# Database
Shared MySQL pool, exposed to all plugins via `DatabaseService` from NetworkCore. Use this for durable state that needs to survive restarts and be queried later: player profiles, punishment history, currency balances, leaderboards, anything you'd run a SQL query against.
For ephemeral observability data (counters, latency), use the metrics layer instead. See [04_Metrics.md](04_Metrics.md).
## API
```java
public interface DatabaseService {
DataSource getDataSource();
boolean isHealthy();
int getActiveConnections();
int getIdleConnections();
int getTotalConnections();
}
```
That's it. We expose the `DataSource` and stay out of your way. Use JDBC directly, jOOQ, MyBatis, JdbcTemplate, whatever you like.
## Getting a connection
Always use try-with-resources so connections return to the pool:
```java
DatabaseService db = NetworkCore.getInstance().getDatabase();
if (db == null) {
// MySQL disabled in NetworkCore config; degrade gracefully
return;
}
try (Connection c = db.getDataSource().getConnection();
PreparedStatement ps = c.prepareStatement("SELECT name, level FROM players WHERE uuid = ?")) {
ps.setString(1, uuid.toString());
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return new PlayerRecord(rs.getString("name"), rs.getInt("level"));
}
}
}
```
Never hold a connection across an RPC call, a thread hop, or a wait. Pool exhaustion is the most common way Hikari-backed plugins fall over.
## Threading
The pool is fully thread-safe. Get a connection from whichever thread needs it. JDBC calls themselves block, so:
- Don't run heavy queries on the Hytale world thread - it stops world ticking.
- Don't run heavy queries on the MessageBus worker pool - it backs up the bus.
- Use a dedicated executor or `CompletableFuture.supplyAsync` for I/O-heavy work.
## Schema management
NetworkCore owns the *pool*, not your schema. Each plugin is responsible for creating and migrating its own tables.
Conventions:
- **Table prefix per plugin.** The Staff plugin prefixes everything with `staff_`. Pick something unique to your plugin so two plugins don't fight over `players`.
- **Bootstrap on startup.** In your plugin's `start()`, run a `CREATE TABLE IF NOT EXISTS ...` for every table you need. This makes a fresh install just-work without manual setup.
- **Migrations as numbered scripts.** When you change a schema, add a `migrations/002_add_email_column.sql` and a tiny runner that tracks applied migrations in a `<plugin>_schema_version` table. Don't reach for Flyway/Liquibase until you've added a third migration - those frameworks earn their weight on real projects, not on the second migration.
## Configuration
See the [mysql section in 03_Configuration.md](03_Configuration.md#mysql). Default is `enabled: false` so a server that doesn't have MySQL configured doesn't crash on boot. Flip to `true` once you've put credentials in place via `MYSQL_PASSWORD` env var.
## What you see in /networkcore status
When MySQL is healthy:
```
Database: ok (active=2 idle=8 total=10)
```
When disabled:
```
Database: disabled
```
When configured but failing:
```
Database: unhealthy
```
If you ever see "unhealthy", check the boot log for the connection error and verify host/port/credentials.
## What is *not* in the box
- **No ORM.** Plain `DataSource` only. Pick your own.
- **No migration framework.** Bootstrap with `CREATE TABLE IF NOT EXISTS` per plugin.
- **No automatic encryption at rest.** That's MySQL's job, not the plugin's. Use MySQL Enterprise's TDE or AWS RDS encryption.
- **No read replicas.** Single pool to a single MySQL endpoint. Read replicas are an MySQL Router or ProxySQL concern, not a Hytale plugin concern.
## Sizing the pool
`max_pool_size = 10` is fine for a single server with a handful of plugins. Rules of thumb:
- Each plugin doing heavy queries needs maybe 2-4 connections worth of headroom.
- The pool is per Hytale-server-instance, not network-wide. If you have 5 servers each with pool=10, MySQL needs to handle 50 concurrent connections.
- Make sure MySQL's `max_connections` is comfortably above the *sum* of all pools that point at it.
Don't crank `max_pool_size` to "fix" pool exhaustion. Pool exhaustion is almost always a leaked connection or a query that's holding the connection too long. Find the leak, then re-evaluate sizing.
+1
View File
@@ -15,6 +15,7 @@ If you're building a plugin that needs to talk to other servers, record stats, o
7. [07_RPC.md](07_RPC.md) - request/response between servers
8. [08_Commands.md](08_Commands.md) - the /networkcore admin command
9. [09_Operations_And_Security.md](09_Operations_And_Security.md) - auth token, what's not secured, ops checks
10. [10_Database.md](10_Database.md) - shared MySQL pool (HikariCP)
## Quick reference