mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 11:41:24 +00:00
iOS/Gateway: stabilize background wake and reconnect behavior (#21226)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 7705a7741e
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
This commit is contained in:
@@ -13,6 +13,7 @@ const mocks = vi.hoisted(() => ({
|
||||
loadApnsRegistration: vi.fn(),
|
||||
resolveApnsAuthConfigFromEnv: vi.fn(),
|
||||
sendApnsBackgroundWake: vi.fn(),
|
||||
sendApnsAlert: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../config/config.js", () => ({
|
||||
@@ -32,6 +33,7 @@ vi.mock("../../infra/push-apns.js", () => ({
|
||||
loadApnsRegistration: mocks.loadApnsRegistration,
|
||||
resolveApnsAuthConfigFromEnv: mocks.resolveApnsAuthConfigFromEnv,
|
||||
sendApnsBackgroundWake: mocks.sendApnsBackgroundWake,
|
||||
sendApnsAlert: mocks.sendApnsAlert,
|
||||
}));
|
||||
|
||||
type RespondCall = [
|
||||
@@ -81,12 +83,17 @@ async function invokeNode(params: {
|
||||
requestParams?: Partial<Record<string, unknown>>;
|
||||
}) {
|
||||
const respond = vi.fn();
|
||||
const logGateway = {
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
};
|
||||
await nodeHandlers["node.invoke"]({
|
||||
params: makeNodeInvokeParams(params.requestParams),
|
||||
respond: respond as never,
|
||||
context: {
|
||||
nodeRegistry: params.nodeRegistry,
|
||||
execApprovalManager: undefined,
|
||||
logGateway,
|
||||
} as never,
|
||||
client: null,
|
||||
req: { type: "req", id: "req-node-invoke", method: "node.invoke" },
|
||||
@@ -135,6 +142,7 @@ describe("node.invoke APNs wake path", () => {
|
||||
mocks.loadApnsRegistration.mockReset();
|
||||
mocks.resolveApnsAuthConfigFromEnv.mockReset();
|
||||
mocks.sendApnsBackgroundWake.mockReset();
|
||||
mocks.sendApnsAlert.mockReset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -202,7 +210,7 @@ describe("node.invoke APNs wake path", () => {
|
||||
expect(call?.[1]).toMatchObject({ ok: true, nodeId: "ios-node-reconnect" });
|
||||
});
|
||||
|
||||
it("throttles repeated wake attempts for the same disconnected node", async () => {
|
||||
it("forces one retry wake when the first wake still fails to reconnect", async () => {
|
||||
vi.useFakeTimers();
|
||||
mockSuccessfulWakeConfig("ios-node-throttle");
|
||||
|
||||
@@ -211,21 +219,14 @@ describe("node.invoke APNs wake path", () => {
|
||||
invoke: vi.fn().mockResolvedValue({ ok: true }),
|
||||
};
|
||||
|
||||
const first = invokeNode({
|
||||
const invokePromise = invokeNode({
|
||||
nodeRegistry,
|
||||
requestParams: { nodeId: "ios-node-throttle", idempotencyKey: "idem-throttle-1" },
|
||||
});
|
||||
await vi.advanceTimersByTimeAsync(WAKE_WAIT_TIMEOUT_MS);
|
||||
await first;
|
||||
await vi.advanceTimersByTimeAsync(20_000);
|
||||
await invokePromise;
|
||||
|
||||
const second = invokeNode({
|
||||
nodeRegistry,
|
||||
requestParams: { nodeId: "ios-node-throttle", idempotencyKey: "idem-throttle-2" },
|
||||
});
|
||||
await vi.advanceTimersByTimeAsync(WAKE_WAIT_TIMEOUT_MS);
|
||||
await second;
|
||||
|
||||
expect(mocks.sendApnsBackgroundWake).toHaveBeenCalledTimes(1);
|
||||
expect(mocks.sendApnsBackgroundWake).toHaveBeenCalledTimes(2);
|
||||
expect(nodeRegistry.invoke).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user