Skip to content

Commit

Permalink
✨ Add heartbeat from sdk to iframe to ensure iframe connection
Browse files Browse the repository at this point in the history
  • Loading branch information
srod committed Dec 16, 2024
1 parent b74b8bb commit 2d47539
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ export function createIFrameRequestResolver(
return;
}
if ("iframeLifecycle" in message.data) {
const { iframeLifecycle } = message.data;
if (iframeLifecycle === "heartbeat") {
setReadyToHandleRequest();
return;
}

console.error(
"Received an iframe lifecycle event on the iframe side, dismissing it"
);
Expand Down
60 changes: 59 additions & 1 deletion sdk/core/src/clients/createIFrameFrakClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,13 @@ export function createIFrameFrakClient({
});
};

// Setup heartbeat
const stopHeartbeat = setupHeartbeat(messageHandler, lifecycleManager);

// Build our destroy function
const destroy = async () => {
// Stop heartbeat
stopHeartbeat();
// Destroy the channel manager
channelManager.destroy();
// Cleanup the message handler
Expand All @@ -181,11 +186,64 @@ export function createIFrameFrakClient({
};
}

/**
* Setup the heartbeat
* @param messageHandler
* @param lifecycleManager
*/
function setupHeartbeat(
messageHandler: IFrameMessageHandler,
lifecycleManager: IframeLifecycleManager
) {
const HEARTBEAT_INTERVAL = 1_000; // Send heartbeat every second
const HEARTBEAT_TIMEOUT = 30_000; // 30 seconds timeout
let heartbeatInterval: NodeJS.Timeout;
let timeoutId: NodeJS.Timeout;

function sendHeartbeat() {
messageHandler.sendEvent({
iframeLifecycle: "heartbeat",
});
}

// Start sending heartbeats
async function startHeartbeat() {
sendHeartbeat(); // Send initial heartbeat
heartbeatInterval = setInterval(sendHeartbeat, HEARTBEAT_INTERVAL);

// Set up timeout
timeoutId = setTimeout(() => {
stopHeartbeat();
console.log("Heartbeat timeout: connection failed");
}, HEARTBEAT_TIMEOUT);

await lifecycleManager.isConnected;

// We are now connected, stop the heartbeat
stopHeartbeat();
}

// Stop sending heartbeats
function stopHeartbeat() {
if (heartbeatInterval) {
clearInterval(heartbeatInterval);
}
if (timeoutId) {
clearTimeout(timeoutId);
}
}

startHeartbeat();

// Return cleanup function
return stopHeartbeat;
}

/**
* Perform the post connection setup
* @param config
* @param lifecycleManager
* @param messageHandler
* @param lifecycleManager
*/
export async function postConnectionSetup({
config,
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/src/types/lifecycle/iframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/
export type IFrameLifecycleEvent =
| {
iframeLifecycle: "connected" | "show" | "hide";
iframeLifecycle: "connected" | "heartbeat" | "show" | "hide";
data?: never;
}
| DoBackupEvent
Expand Down

0 comments on commit 2d47539

Please sign in to comment.