mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-15 23:24:52 +09:00
Keep auto paused instances paused
Every RCON command makes an auto paused Factorio server run one tick, so subspace_storage's 1 s inventory update and 5 s ping, plus a statistics_exporter gather on every Prometheus scrape, kept a server with nobody online running at about 1.3 ticks per second. The instance now records the auto_pause server setting it was started with and exposes autoPaused, true while that setting is on and no players are online, along with an autoPauseChanged hook. subspace_storage skips its timers while paused and sends a ping and inventory as soon as a player joins. statistics_exporter gathers once after the game pauses and keeps serving those values until it resumes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ebdbb1fe56
commit
11e067a933
11 files changed
+227
-19
No files matched your search
@@ -418,6 +418,42 @@ describe("class Instance", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe(".autoPaused", function() {
|
||||
let changes;
|
||||
beforeEach(function() {
|
||||
changes = [];
|
||||
instance.hooks.autoPauseChanged.attach("test", async paused => { changes.push(paused); });
|
||||
});
|
||||
|
||||
it("should be false when auto_pause is off", function() {
|
||||
assert.equal(instance.autoPaused, false);
|
||||
instance._recordPlayerJoin("player");
|
||||
instance._recordPlayerLeave("player", "quit");
|
||||
assert.equal(instance.autoPaused, false);
|
||||
assert.deepEqual(changes, []);
|
||||
});
|
||||
it("should follow players online when auto_pause is on", function() {
|
||||
instance._autoPause = true;
|
||||
assert.equal(instance.autoPaused, true);
|
||||
instance._recordPlayerJoin("a");
|
||||
instance._recordPlayerJoin("b");
|
||||
assert.equal(instance.autoPaused, false);
|
||||
instance._recordPlayerLeave("a", "quit");
|
||||
assert.equal(instance.autoPaused, false);
|
||||
instance._recordPlayerLeave("b", "quit");
|
||||
assert.equal(instance.autoPaused, true);
|
||||
assert.deepEqual(changes, [false, true]);
|
||||
});
|
||||
it("should not invoke the hook on exit", function() {
|
||||
instance._autoPause = true;
|
||||
instance._recordPlayerJoin("player");
|
||||
instance._saveStats = async () => {};
|
||||
instance.notifyExit();
|
||||
assert.equal(instance.autoPaused, false);
|
||||
assert.deepEqual(changes, [false]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("._checkOnlinePlayers()", function() {
|
||||
it("should do nothing on empty server", async function() {
|
||||
await instance._checkOnlinePlayers();
|
||||
|
||||
@@ -1332,6 +1332,55 @@ describe("Integration of Clusterio", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("auto pause", function() {
|
||||
requiresFactorio(this);
|
||||
async function getTick() {
|
||||
return Number(await getControl().sendTo(
|
||||
{ instanceId: 44 }, new lib.InstanceSendRconRequest("/sc rcon.print(game.tick)")
|
||||
));
|
||||
}
|
||||
async function sendPlayerEvent(type) {
|
||||
const json = JSON.stringify({ type, name: "auto_pause_player", reason: "quit" });
|
||||
await getControl().sendTo(
|
||||
{ instanceId: 44 },
|
||||
new lib.InstanceSendRconRequest(`/sc print("\\f$ipc:player_event?j${lib.escapeString(json)}")`),
|
||||
);
|
||||
}
|
||||
let started = false;
|
||||
before(async function() {
|
||||
slowTest(this);
|
||||
this.timeout(60000);
|
||||
started = true;
|
||||
await execCtl("instance stop test");
|
||||
await execCtl("instance config set-prop test factorio.settings auto_pause true");
|
||||
await execCtl("instance start test");
|
||||
});
|
||||
after(async function() {
|
||||
if (!started) {
|
||||
return;
|
||||
}
|
||||
this.timeout(60000);
|
||||
await execCtl("instance stop test");
|
||||
await execCtl("instance config set-prop test factorio.settings auto_pause false");
|
||||
await execCtl("instance start test");
|
||||
});
|
||||
it("does not tick the game while no players are online", async function() {
|
||||
slowTest(this);
|
||||
const start = await getTick();
|
||||
await wait(6000);
|
||||
assert.equal(await getTick() - start, 1);
|
||||
});
|
||||
it("resumes plugin work when a player joins", async function() {
|
||||
slowTest(this);
|
||||
const start = await getTick();
|
||||
await sendPlayerEvent("join");
|
||||
await wait(6000);
|
||||
const ticks = await getTick() - start;
|
||||
await sendPlayerEvent("leave");
|
||||
assert(ticks > 3, `game ran ${ticks} ticks`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("instance stop", function() {
|
||||
it("stops the instance", async function() {
|
||||
slowTest(this);
|
||||
|
||||
@@ -129,6 +129,7 @@ export class MockInstance extends lib.Link {
|
||||
this.name = "test";
|
||||
this.id = 7357;
|
||||
this.status = "running";
|
||||
this.autoPaused = false;
|
||||
this.hooks = new InstanceHooks(this.logger);
|
||||
this.loadedPlugins = new Set();
|
||||
this.mockConfigEntries = new Map([
|
||||
|
||||
Reference in new issue
Block a user