refactor(ext): drive heartbeat and running flag from statuschange
Project agent status into chrome.storage via a statuschange listener instead of pairing setup/teardown across lifecycle hooks. A throwing hook can no longer leak the heartbeat or strand isAgentRunning, and rejected concurrent execute() calls never touch the active run's state.
This commit is contained in:
@@ -39,15 +39,6 @@ export class MultiPageAgent extends PageAgentCore {
|
|||||||
const includeInitialTab = config.includeInitialTab ?? true
|
const includeInitialTab = config.includeInitialTab ?? true
|
||||||
const experimentalIncludeAllTabs = config.experimentalIncludeAllTabs ?? false
|
const experimentalIncludeAllTabs = config.experimentalIncludeAllTabs ?? false
|
||||||
|
|
||||||
/**
|
|
||||||
* When the agent is in side-panel and user closed the side-panel.
|
|
||||||
* There is no chance for isAgentRunning to be set false.
|
|
||||||
* (unload event doesn't work well in side panel.)
|
|
||||||
* (I'm trying not to use long-lived connection because the lifecycle of a sw is hard to predict.)
|
|
||||||
* This heartbeat mechanism acts as a backup.
|
|
||||||
*/
|
|
||||||
let heartBeatInterval: null | number = null
|
|
||||||
|
|
||||||
super({
|
super({
|
||||||
...config,
|
...config,
|
||||||
pageController: pageController as any,
|
pageController: pageController as any,
|
||||||
@@ -56,27 +47,6 @@ export class MultiPageAgent extends PageAgentCore {
|
|||||||
|
|
||||||
onBeforeTask: async (agent) => {
|
onBeforeTask: async (agent) => {
|
||||||
await tabsController.init(agent.task, { includeInitialTab, experimentalIncludeAllTabs })
|
await tabsController.init(agent.task, { includeInitialTab, experimentalIncludeAllTabs })
|
||||||
|
|
||||||
heartBeatInterval = window.setInterval(() => {
|
|
||||||
chrome.storage.local.set({
|
|
||||||
agentHeartbeat: Date.now(),
|
|
||||||
})
|
|
||||||
}, 1_000)
|
|
||||||
|
|
||||||
await chrome.storage.local.set({
|
|
||||||
isAgentRunning: true,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
onAfterTask: async () => {
|
|
||||||
if (heartBeatInterval) {
|
|
||||||
window.clearInterval(heartBeatInterval)
|
|
||||||
heartBeatInterval = null
|
|
||||||
}
|
|
||||||
|
|
||||||
await chrome.storage.local.set({
|
|
||||||
isAgentRunning: false,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onBeforeStep: async (agent) => {
|
onBeforeStep: async (agent) => {
|
||||||
@@ -86,17 +56,35 @@ export class MultiPageAgent extends PageAgentCore {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onDispose: () => {
|
onDispose: () => {
|
||||||
if (heartBeatInterval) {
|
|
||||||
window.clearInterval(heartBeatInterval)
|
|
||||||
heartBeatInterval = null
|
|
||||||
}
|
|
||||||
|
|
||||||
chrome.storage.local.set({
|
|
||||||
isAgentRunning: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
tabsController.dispose()
|
tabsController.dispose()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project agent status into chrome.storage. The content script polls
|
||||||
|
* `isAgentRunning` + `agentHeartbeat` (eventually consistent by design).
|
||||||
|
*
|
||||||
|
* When the agent is in side-panel and user closed the side-panel.
|
||||||
|
* There is no chance for isAgentRunning to be set false.
|
||||||
|
* (unload event doesn't work well in side panel.)
|
||||||
|
* (I'm trying not to use long-lived connection because the lifecycle of a sw is hard to predict.)
|
||||||
|
* This heartbeat mechanism acts as a backup.
|
||||||
|
*/
|
||||||
|
let heartBeatInterval: number | null = null
|
||||||
|
|
||||||
|
this.addEventListener('statuschange', () => {
|
||||||
|
const running = this.status === 'running'
|
||||||
|
|
||||||
|
if (running && !heartBeatInterval) {
|
||||||
|
heartBeatInterval = window.setInterval(() => {
|
||||||
|
void chrome.storage.local.set({ agentHeartbeat: Date.now() })
|
||||||
|
}, 1_000)
|
||||||
|
} else if (!running && heartBeatInterval) {
|
||||||
|
clearInterval(heartBeatInterval)
|
||||||
|
heartBeatInterval = null
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.storage.local.set({ isAgentRunning: running }).catch(console.error)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user