fix: less verbose sandbox daemon

This commit is contained in:
Guillaume ARM 2026-06-15 18:31:42 +02:00
parent fd36bded49
commit c9fe4ca50a
6 changed files with 76 additions and 11 deletions

View File

@ -201,6 +201,10 @@ local function createSandbox()
local state = 'connecting';
local lastError = nil;
local activeWs = nil;
-- True while looping on retries. Gates the per-attempt chatter (connecting / socket
-- open / connection failed / connection closed) so a long outage logs once on entry
-- and once on recovery instead of flooding the file every reconnectDelay seconds.
local reconnecting = false;
local function sendFrame(frame)
if not activeWs then
@ -218,7 +222,9 @@ local function createSandbox()
local function connect()
state = 'connecting';
if not reconnecting then
log('info', 'connecting', { url = url });
end
httpLike.websocketAsync(url);
end
@ -228,7 +234,12 @@ local function createSandbox()
return;
end
state = 'connecting';
log('info', 'reconnect scheduled', { delaySeconds = reconnectDelay });
-- One line on the false->true transition, then silence: every later retry runs
-- through here too, but we keep trying without re-logging.
if not reconnecting then
reconnecting = true;
log('warn', 'reconnect loop started', { delaySeconds = reconnectDelay });
end
el.setTimeout(connect, reconnectDelay);
end
@ -238,7 +249,12 @@ local function createSandbox()
end
if ok then
state = 'ready';
if reconnecting then
reconnecting = false;
log('info', 'reconnect loop ended; reconnected', { traposId = traposId });
else
log('info', 'connected', { traposId = traposId });
end
queueEvent('trapos_sandbox_connected', traposId);
else
state = 'unauthorized';
@ -252,7 +268,9 @@ local function createSandbox()
if eventUrl ~= url then return; end
activeWs = ws;
state = 'awaiting_hello';
if not reconnecting then
log('info', 'socket open; sending hello', { traposId = traposId });
end
sendFrame(api.buildHello(traposId, secret, makeUuid(opts.random)));
-- hello-ack watchdog: state-guarded, no stored cancel. If hello already
-- resolved this is a harmless no-op; closing triggers reconnect.
@ -276,7 +294,9 @@ local function createSandbox()
el.register('websocket_failure', function(eventUrl)
if eventUrl ~= url then return; end
if not reconnecting then
log('warn', 'connection failed', { url = url });
end
scheduleReconnect();
end);
@ -300,7 +320,9 @@ local function createSandbox()
end
return;
end
if not reconnecting then
log('info', 'connection closed', { code = code, reason = reason });
end
scheduleReconnect();
end);

View File

@ -1,6 +1,6 @@
{
"name": "TrapOS",
"version": "0.9.3",
"version": "0.9.4",
"branch": "master",
"packages": [
"trapos"

View File

@ -6,8 +6,8 @@
"trapos-net": "0.3.0",
"trapos-ui": "0.2.2",
"trapos-ai": "0.7.0",
"trapos-sandbox": "0.2.5",
"trapos-sandbox": "0.2.6",
"trapos-sandbox-legacy": "0.2.2",
"trapos": "0.9.3"
"trapos": "0.9.4"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "trapos-sandbox",
"version": "0.2.5",
"version": "0.2.6",
"description": "TrapOS sandbox gateway client: WS daemon (servers/sandbox) + sandbox command",
"dependencies": ["trapos-core"],
"files": [

View File

@ -1,6 +1,6 @@
{
"name": "trapos",
"version": "0.9.3",
"version": "0.9.4",
"description": "TrapOS full install meta-package",
"dependencies": [
"trapos-boot",

View File

@ -234,6 +234,49 @@ testlib.test('startSession reconnects on an abnormal close with a non-displaced
testlib.assertEquals(#ctx.http.connects, 2);
end);
testlib.test('startSession logs the reconnect loop once on entry and once on recovery', function()
local logs = {};
local function countMsg(msg)
local n = 0;
for _, entry in ipairs(logs) do
if entry.msg == msg then n = n + 1; end
end
return n;
end
local ctx = startSession({
log = function(level, msg, fields) logs[#logs + 1] = { level = level, msg = msg, fields = fields }; end,
});
-- Healthy connect: no reconnect-loop logs yet.
ctx.el.fire('websocket_success', ctx.url, fakes.fakeWs());
ctx.el.fire('websocket_message', ctx.url, encode({ event = 'gateway_response', type = 'hello', ok = true, payload = {} }));
testlib.assertEquals(ctx.session.isReady(), true);
testlib.assertEquals(countMsg('reconnect loop started'), 0);
-- Drop, then fail the retry several times: the loop is announced exactly once and the
-- per-attempt chatter (connecting / connection failed) does not repeat while looping.
ctx.el.fire('websocket_closed', ctx.url);
local connectingBefore = countMsg('connecting');
for _ = 1, 3 do
ctx.el.fireTimer(#ctx.el.timers); -- reconnect timer -> connect()
ctx.el.fire('websocket_failure', ctx.url); -- retry fails, schedules the next timer
end
testlib.assertEquals(countMsg('reconnect loop started'), 1);
testlib.assertEquals(countMsg('connection closed'), 1); -- the first drop logged, not the retries
testlib.assertEquals(countMsg('connecting'), connectingBefore); -- suppressed while looping
testlib.assertEquals(countMsg('connection failed'), 0); -- suppressed while looping
-- Recovery: a single "reconnected" line, no second "loop started".
ctx.el.fireTimer(#ctx.el.timers); -- reconnect timer -> connect()
ctx.el.fire('websocket_success', ctx.url, fakes.fakeWs());
ctx.el.fire('websocket_message', ctx.url, encode({ event = 'gateway_response', type = 'hello', ok = true, payload = {} }));
testlib.assertEquals(ctx.session.isReady(), true);
testlib.assertEquals(countMsg('reconnect loop ended; reconnected'), 1);
testlib.assertEquals(countMsg('reconnect loop started'), 1);
end);
testlib.test('startSession treats a displacement close (4000) as terminal', function()
local ctx = startSession();
local ws = fakes.fakeWs();