mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-11 10:57:07 +00:00
fix(server): stop liveness pings on plugin sessions
Every DaemonClient pings its daemon every 10 s to notice a silently dead socket. A plugin's
session runs over its IPC channel (or an in-process queue for built-in plugins), whose loss is
reported directly, and the daemon already exempts plugin sockets from the application lease those
pings renew. The pings only woke both processes: about 2 wakeups a second in an idle daemon with
nine plugins and the built-ins.
DaemonClient gets a livenessHeartbeat option (default on); the plugin host turns it off.
Explicit verification (ensureConnected({ verify: true })) still pings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d46ee6558c
commit
fb435d225f
@@ -753,13 +753,14 @@ class DaemonClientSession {
|
||||
private readonly daemon = new FakeDaemon();
|
||||
private readonly client: DaemonClient;
|
||||
|
||||
constructor() {
|
||||
constructor(options: { livenessHeartbeat?: boolean } = {}) {
|
||||
this.client = new DaemonClient({
|
||||
url: "ws://test",
|
||||
clientId: "clsk_heartbeat_test",
|
||||
logger: noopLogger,
|
||||
reconnect: { enabled: false },
|
||||
transportFactory: () => this.daemon.transport,
|
||||
...options,
|
||||
});
|
||||
clients.push(this.client);
|
||||
}
|
||||
@@ -3257,6 +3258,18 @@ test("starts pinging one interval after connecting and holds the cadence", async
|
||||
expect(session.pingTimestamps()).toEqual(["10s", "20s", "30s"]);
|
||||
});
|
||||
|
||||
test("a client with the liveness heartbeat off never pings on its own", async () => {
|
||||
useHeartbeatClock();
|
||||
const session = new DaemonClientSession({ livenessHeartbeat: false });
|
||||
session.daemonAnswersPingsAfter("fast");
|
||||
|
||||
await session.connect();
|
||||
await session.advance(60_000);
|
||||
|
||||
expect(session.state()).toEqual({ status: "connected" });
|
||||
expect(session.pingTimestamps()).toEqual([]);
|
||||
});
|
||||
|
||||
test("stops pinging once the connection is gone", async () => {
|
||||
useHeartbeatClock();
|
||||
const session = new DaemonClientSession();
|
||||
|
||||
@@ -469,6 +469,13 @@ export interface DaemonClientConfig {
|
||||
runtimeMetricsWindowMs?: number;
|
||||
trace?: DaemonClientTrace;
|
||||
capabilities?: Partial<Record<ClientCapability, unknown>>;
|
||||
/**
|
||||
* Ping the daemon every 10 s and reconnect after missed replies (default true). Turn it off
|
||||
* only where the transport reports its own loss (a plugin's IPC channel, an in-process
|
||||
* channel): there a ping cannot find a dead link the channel would not, and it costs both
|
||||
* processes a wakeup per client every 10 s.
|
||||
*/
|
||||
livenessHeartbeat?: boolean;
|
||||
}
|
||||
|
||||
export interface DaemonClientTrace {
|
||||
@@ -2720,7 +2727,11 @@ export class DaemonClient {
|
||||
}
|
||||
|
||||
private scheduleNextLivenessHeartbeat(): void {
|
||||
if (this.connectionState.status !== "connected" || this.livenessHeartbeatTimer) {
|
||||
if (
|
||||
this.config.livenessHeartbeat === false ||
|
||||
this.connectionState.status !== "connected" ||
|
||||
this.livenessHeartbeatTimer
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.livenessHeartbeatTimer = setTimeout(() => {
|
||||
|
||||
@@ -313,6 +313,9 @@ export function createPluginWorker(options: {
|
||||
// The runtime re-attaches a session when the daemon drops this socket.
|
||||
reconnect: { enabled: true },
|
||||
transportFactory,
|
||||
// The channel is a pipe to the daemon (or an in-process queue for built-in plugins); its
|
||||
// loss is reported directly, so a 10 s ping would only wake both sides.
|
||||
livenessHeartbeat: false,
|
||||
});
|
||||
paseo = createPaseoApi(daemonClient);
|
||||
await daemonClient.connect();
|
||||
|
||||
Reference in New Issue
Block a user