Summary
On a Perry-native Linux x86_64 binary, socket.write(buf) is silently dropped (no sendto syscall, bytes never hit the wire) when the socket is reached through a property of a Map-stored object and the write happens from a timer (setInterval) callback. The identical write through a top-level const socket from the same timer context works.
This is distinct from #5021 (write-from-'data'-handler, now fixed). It blocks @perryts/mysql again: its 0.1.7 fix correctly detects Perry (process.versions.perry) and defers writes to a setInterval flush pump, but the pump writes via CONN_STATES.get(id).sock.write(bytes) — exactly the dropped pattern — so password auth still times out (Got timeout reading communication packets).
Minimal repro
Dropped — 0 sendto:
import * as net from 'net';
interface St { sock: ReturnType<typeof net.createConnection>; }
const M = new Map<number, St>(); const id = 1;
M.set(id, { sock: net.createConnection(3306, '127.0.0.1') }); // any peer that speaks first
let done = false;
function flush(i: number): void { const st = M.get(i); if (st === undefined) return; st.sock.write(Buffer.alloc(105, 0x41)); }
M.get(id)!.sock.on('data', () => {
if (done) return; done = true;
const iv = setInterval(() => { flush(id); clearInterval(iv); }, 0);
setTimeout(() => process.exit(0), 2000);
});
perry compile repro.ts -o r && strace -f -e trace=sendto ./r → no sendto(…, 105).
Works — sendto fires: the same write but on a top-level const socket directly inside the setInterval (no Map/object-property indirection):
const iv = setInterval(() => { s.write(Buffer.alloc(105, 0x41)); clearInterval(iv); }, 0); // s = module const
Observed in the real driver (@perryts/mysql 0.1.7)
Instrumented trace of a password connect:
recv len=94 # greeting
scheduleFlush q=1
PUMP fired # setInterval pump runs
FLUSH id=1
flush-write len=105 # st.sock.write(bytes) is called ...
<no sendto> # ... but nothing reaches the wire
failStartup connection timeout after 10000ms
Environment
perry 0.5.1182 (runtime reports process.versions.perry = 0.4.71), Ubuntu 26.04 x86_64, MySQL 8.4. Empty-password connections work (zero-length auth response ⇒ the failing write path isn't exercised); Node works. Companion: PerryTS/mysql#2.
Summary
On a Perry-native Linux x86_64 binary,
socket.write(buf)is silently dropped (nosendtosyscall, bytes never hit the wire) when the socket is reached through a property of aMap-stored object and the write happens from a timer (setInterval) callback. The identical write through a top-levelconstsocket from the same timer context works.This is distinct from #5021 (write-from-
'data'-handler, now fixed). It blocks@perryts/mysqlagain: its 0.1.7 fix correctly detects Perry (process.versions.perry) and defers writes to asetIntervalflush pump, but the pump writes viaCONN_STATES.get(id).sock.write(bytes)— exactly the dropped pattern — so password auth still times out (Got timeout reading communication packets).Minimal repro
Dropped — 0
sendto:perry compile repro.ts -o r && strace -f -e trace=sendto ./r→ nosendto(…, 105).Works —
sendtofires: the same write but on a top-levelconstsocket directly inside thesetInterval(noMap/object-property indirection):Observed in the real driver (@perryts/mysql 0.1.7)
Instrumented trace of a password connect:
Environment
perry 0.5.1182 (runtime reports
process.versions.perry = 0.4.71), Ubuntu 26.04 x86_64, MySQL 8.4. Empty-password connections work (zero-length auth response ⇒ the failing write path isn't exercised); Node works. Companion: PerryTS/mysql#2.