mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-23 22:01:21 +00:00
fix: pause hidden session catalog polling
This commit is contained in:
@@ -175,12 +175,11 @@ export abstract class AppSidebarSessionDataElement extends AppSidebarBase {
|
||||
|
||||
override updated() {
|
||||
this.syncSessionsScrollObserver();
|
||||
const snapshot = this.context?.gateway.snapshot;
|
||||
if (this.context) {
|
||||
this.synchronizeSessionCatalogAgent(this.expandedAgentId());
|
||||
}
|
||||
if (
|
||||
!sessionCatalogListClient(snapshot, this.connected) ||
|
||||
!this.visibleSessionCatalogClient() ||
|
||||
this.sessionCatalogLive.timer ||
|
||||
this.sessionCatalogLive.requestGeneration === this.sessionCatalogGeneration
|
||||
) {
|
||||
@@ -189,6 +188,13 @@ export abstract class AppSidebarSessionDataElement extends AppSidebarBase {
|
||||
void this.refreshSessionCatalogs();
|
||||
}
|
||||
|
||||
private visibleSessionCatalogClient(): GatewayBrowserClient | null {
|
||||
if (document.visibilityState === "hidden") {
|
||||
return null;
|
||||
}
|
||||
return sessionCatalogListClient(this.context?.gateway.snapshot, this.connected);
|
||||
}
|
||||
|
||||
private synchronizeSessionCatalogAgent(agentId: string) {
|
||||
if (agentId === this.sessionCatalogAgentId) {
|
||||
return;
|
||||
@@ -265,7 +271,9 @@ export abstract class AppSidebarSessionDataElement extends AppSidebarBase {
|
||||
}
|
||||
|
||||
private async refreshSessionCatalogs() {
|
||||
const client = sessionCatalogListClient(this.context?.gateway.snapshot, this.connected);
|
||||
// Hidden pages resume through the coalesced activation handler. Starting
|
||||
// here without a timer makes catalog state updates poll at request latency.
|
||||
const client = this.visibleSessionCatalogClient();
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { SessionsCatalogListResult } from "../../../../packages/gateway-protocol/src/index.ts";
|
||||
import type { GatewayBrowserClient } from "../../api/gateway.ts";
|
||||
import type { ApplicationGatewaySnapshot } from "../../app/context.ts";
|
||||
import { catalogPage, createGatewayHarness, createSessions, mountSidebar } from "../app-sidebar.ts";
|
||||
import {
|
||||
catalogPage,
|
||||
createGatewayHarness,
|
||||
createSessions,
|
||||
deferred,
|
||||
mountSidebar,
|
||||
} from "../app-sidebar.ts";
|
||||
import "../../components/app-sidebar.ts";
|
||||
|
||||
describe("AppSidebar session catalog pagination", () => {
|
||||
@@ -44,6 +51,56 @@ describe("AppSidebar session catalog pagination", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("stays paused when an in-flight catalog refresh finishes in a hidden tab", async () => {
|
||||
vi.useFakeTimers();
|
||||
let visibility: DocumentVisibilityState = "visible";
|
||||
const visibilitySpy = vi
|
||||
.spyOn(document, "visibilityState", "get")
|
||||
.mockImplementation(() => visibility);
|
||||
try {
|
||||
const pending = deferred<SessionsCatalogListResult>();
|
||||
const request = vi
|
||||
.fn()
|
||||
.mockReturnValueOnce(pending.promise)
|
||||
.mockResolvedValue(catalogPage([]));
|
||||
const gateway = createGatewayHarness({ request } as unknown as GatewayBrowserClient);
|
||||
gateway.publish({
|
||||
hello: {
|
||||
features: { methods: ["sessions.catalog.list"] },
|
||||
} as ApplicationGatewaySnapshot["hello"],
|
||||
});
|
||||
const { sidebar } = await mountSidebar(
|
||||
gateway.gateway,
|
||||
createSessions("main", ["agent:main:main"]),
|
||||
);
|
||||
sidebar.connected = true;
|
||||
await sidebar.updateComplete;
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
expect(request).toHaveBeenCalledTimes(1);
|
||||
|
||||
visibility = "hidden";
|
||||
document.dispatchEvent(new Event("visibilitychange"));
|
||||
pending.resolve(catalogPage([]));
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
await sidebar.updateComplete;
|
||||
await vi.advanceTimersByTimeAsync(60_000);
|
||||
expect(request).toHaveBeenCalledTimes(1);
|
||||
|
||||
visibility = "visible";
|
||||
document.dispatchEvent(new Event("visibilitychange"));
|
||||
globalThis.dispatchEvent(new Event("focus"));
|
||||
await vi.advanceTimersByTimeAsync(49);
|
||||
expect(request).toHaveBeenCalledTimes(1);
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
expect(request).toHaveBeenCalledTimes(2);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
expect(request).toHaveBeenCalledTimes(2);
|
||||
} finally {
|
||||
visibilitySpy.mockRestore();
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it("does not poll an older Gateway that does not advertise session catalogs", async () => {
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user