perf(web ui):keep alive consumer (#2325)

This commit is contained in:
xudaotutou 2022-10-28 04:39:47 -05:00 committed by GitHub
parent aa2526075b
commit 18e8f6b5d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 124 additions and 32 deletions

View File

@ -422,6 +422,7 @@ type CommandResult = {
} | { } | {
options: GlobalOptions[]; options: GlobalOptions[];
changeResult: { changeResult: {
"afterValue": unknown, "afterValue": unknown,
"beforeValue": unknown, "beforeValue": unknown,
"name": string "name": string
@ -709,7 +710,9 @@ type ArthasRes = CommonRes | SessionRes | FailRes | AsyncRes;
type BindQS = type BindQS =
| { req: CommandReq; res: CommonRes } | { req: CommandReq; res: CommonRes }
| { req: SessionReq; res: SessionRes } | { req: SessionReq; res: SessionRes }
| { req: AsyncReq; res: AsyncRes }; | { req: AsyncReq; res: AsyncRes }
| { req: PullResults; res: ArthasRes };
// autoComplete // autoComplete
type Item = { name: string; value: unknown }; type Item = { name: string; value: unknown };

View File

@ -26,7 +26,10 @@ publicS.getCommonResEffect(fetchM, body => {
const result = body.results[0] const result = body.results[0]
if (result.type === "version") { if (result.type === "version") {
version.value = result.version version.value = result.version
}})
}
})
watchEffect(() => { watchEffect(() => {
if (!fetchS.wait) restBtnclass.value = "animate-spin-rev-pause" if (!fetchS.wait) restBtnclass.value = "animate-spin-rev-pause"
@ -68,20 +71,12 @@ const logout = async () => {
interruptEvent() interruptEvent()
sessionM.send("SUBMIT", { fetchS.closeSession()
value: {
action: "close_session",
sessionId: undefined
}
})
restBtnclass.value = "animate-spin-rev-pause" restBtnclass.value = "animate-spin-rev-pause"
} }
const login = async () => {
sessionM.send("SUBMIT", { const login = () => {
value: { fetchS.initSession()
action: "init_session"
}
})
} }
const shutdown = () => { const shutdown = () => {
publicS.warnMessage = "Are you sure to stop the arthas? All the Arthas clients connecting to this server will be disconnected." publicS.warnMessage = "Are you sure to stop the arthas? All the Arthas clients connecting to this server will be disconnected."
@ -134,6 +129,7 @@ const tabs = [
icon: TerminalIcon icon: TerminalIcon
}, },
{ {
name:'terminal', name:'terminal',
url:'terminal', url:'terminal',
icon:TerminalIcon icon:TerminalIcon
@ -148,8 +144,8 @@ const tools: [string, () => void][] = [
const router = useRouter() const router = useRouter()
const routePath = computed(() => useRoute().path) const routePath = computed(() => useRoute().path)
const toNext = (url: string) => { const toNext = (url: string) => {
if(url === "terminal") { if (url === "terminal") {
window.open("/","_blank") window.open("/", "_blank")
} else router.push(url) } else router.push(url)
} }
</script> </script>
@ -158,11 +154,11 @@ const toNext = (url: string) => {
<nav class=" h-[10vh] border-b-2 navbar"> <nav class=" h-[10vh] border-b-2 navbar">
<div class=" navbar-start flex items-stretch "> <div class=" navbar-start flex items-stretch ">
<!-- <div class=" indicator mx-3"> --> <!-- <div class=" indicator mx-3"> -->
<a class="flex items-center justify-center mx-2" href="https://arthas.aliyun.com/doc/commands.html" <a class="flex items-center justify-center mx-2" href="https://arthas.aliyun.com/doc/commands.html"
target="_blank"> target="_blank">
<img src="/arthas.png" alt="logo" class="w-32" /> <img src="/arthas.png" alt="logo" class="w-32" />
</a> </a>
<span class="badge badge-ghost self-end text-sm">v{{version}}</span> <span class="badge badge-ghost self-end text-sm">v{{ version }}</span>
<!-- </div> --> <!-- </div> -->
</div> </div>
<div class="navbar-center"> <div class="navbar-center">
@ -171,7 +167,7 @@ const toNext = (url: string) => {
<a class="break-all" :class="{ 'bg-primary text-primary-content': routePath.includes(tab.url), }"> <a class="break-all" :class="{ 'bg-primary text-primary-content': routePath.includes(tab.url), }">
<component :is="tab.icon" class="w-4 h-4" /> <component :is="tab.icon" class="w-4 h-4" />
{{ {{
tab.name tab.name
}} }}
</a> </a>
</li> </li>

View File

@ -443,7 +443,7 @@ const permachine = createMachine({
isCommon: (context) => { isCommon: (context) => {
if (!context) return false; if (!context) return false;
if ( if (
["exec"] ["exec","pull_results"]
.includes(context.inputValue!.action) .includes(context.inputValue!.action)
) { ) {
console.log("isCommon"); console.log("isCommon");
@ -454,7 +454,7 @@ const permachine = createMachine({
isAsync: (context) => { isAsync: (context) => {
if (!context) return false; if (!context) return false;
if ( if (
["async_exec", "pull_results"] ["async_exec"]
.includes(context.inputValue!.action) .includes(context.inputValue!.action)
) { ) {
console.log("isAsync"); console.log("isAsync");

View File

@ -12,6 +12,10 @@ const router = createRouter({
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
fetchStore() fetchStore()
.interruptJob() .interruptJob()
.catch(_=>{
// console.error(e)
// 拦截调试台的错误
})
.finally(() => { .finally(() => {
next(); next();
}); });

View File

@ -27,7 +27,8 @@ type PollingLoop = {
invoke(): void; invoke(): void;
}; };
const nullLoop: PollingLoop = { const nullLoop: PollingLoop = {
open() {}, open() {
},
close() {}, close() {},
isOn() { isOn() {
return false; return false;
@ -48,11 +49,11 @@ export const fetchStore = defineStore("fetch", {
// 所有用pollingLoop都要 // 所有用pollingLoop都要
jobRunning: false, jobRunning: false,
// 对于 pullresults可能会拉同一个结果很多次 // 对于 pullresults可能会拉同一个结果很多次
jobIdSet: new Set<string>(), // jobIdSet: new Set<string>(),
//由于轮询只会轮询一个命令,可以直接挂载当前的轮询机 //由于轮询只会轮询一个命令,可以直接挂载当前的轮询机
curPolling: nullLoop, curPolling: nullLoop,
//获取osName 通过dashboard //对session init以后4分钟重轮一次。
osName:"" // 如果curPolling是nullLoop,就要停掉状态维持来防止消耗异步请求结果的行为
}), }),
getters: { getters: {
getRequest: (state) => getRequest: (state) =>
@ -94,6 +95,15 @@ export const fetchStore = defineStore("fetch", {
}, },
}, },
actions: { actions: {
/**
* @param hander 使
* @param options stepglobalIntrupt: 是否需要全局的打断按钮
* @returns
* open以后才挂载到curPolling
* close以后会重置为nullLoop
* curloop的状态转移
* nullloop->keepalive loop->polling loop
*/
getPollingLoop( getPollingLoop(
hander: Function, hander: Function,
options: { step?: number; globalIntrupt?: boolean } = { options: { step?: number; globalIntrupt?: boolean } = {
@ -104,10 +114,16 @@ export const fetchStore = defineStore("fetch", {
let id = -1; let id = -1;
const { step, globalIntrupt } = options; const { step, globalIntrupt } = options;
const that = this; const that = this;
const pollingLoop = { // 很有可能是keepalive session loop
let preLoop = this.curPolling;
const pollingLoop: PollingLoop = {
// 自动轮询的可能会被错误打断 // 自动轮询的可能会被错误打断
open() { open() {
if (!this.isOn()) { if (!this.isOn()) {
// 切换为当前用到的 pollingLoop
preLoop.close();
that.curPolling = pollingLoop;
if (globalIntrupt) that.jobRunning = true; if (globalIntrupt) that.jobRunning = true;
hander(); hander();
id = setInterval( id = setInterval(
@ -131,6 +147,10 @@ export const fetchStore = defineStore("fetch", {
if (globalIntrupt) that.jobRunning = false; if (globalIntrupt) that.jobRunning = false;
clearInterval(id); clearInterval(id);
id = -1; id = -1;
// 重置为默认的nullloop
that.curPolling = preLoop;
// 继续keepalive
preLoop.open();
} }
}, },
isOn() { isOn() {
@ -143,10 +163,9 @@ export const fetchStore = defineStore("fetch", {
hander(); hander();
}, },
}; };
this.curPolling = pollingLoop;
return pollingLoop; return pollingLoop;
}, },
pullResultsLoop(pollingM: Machine,globalIntrupt:boolean=true) { pullResultsLoop(pollingM: Machine, globalIntrupt: boolean = true) {
return this.getPollingLoop( return this.getPollingLoop(
() => { () => {
pollingM.send({ pollingM.send({
@ -163,6 +182,9 @@ export const fetchStore = defineStore("fetch", {
}, },
); );
}, },
/**
*
*/
onWait() { onWait() {
if (!this.wait) this.wait = true; if (!this.wait) this.wait = true;
}, },
@ -245,10 +267,71 @@ export const fetchStore = defineStore("fetch", {
}, },
); );
}, },
keepaliveSession() {
const kl = () => {
let m = interpret(permachine);
m.start();
m.send("INIT");
m.send({
type: "SUBMIT",
value: {
action: "pull_results",
sessionId: undefined,
consumerId: undefined,
},
});
};
kl();
let id = -1;
let that = this;
let loop = {
open() {
if (!this.isOn()) {
// 切换为kl_loop
that.curPolling.close();
that.curPolling = loop;
kl();
id = setInterval(
(() => {
if (
// 不在线或者意外报错就停掉
publicStore().isErr || !that.online
) {
this.close();
} else {
kl();
}
}) as TimerHandler,
60_000,
);
}
},
close() {
if (this.isOn()) {
clearInterval(id);
id = -1;
// 重置为默认的nullloop
that.curPolling = nullLoop;
}
},
isOn() {
return id !== -1;
},
invoke() {},
};
// 会先运行一次,当有任务执行
loop.open();
return loop;
},
initSession() { initSession() {
return this.baseSubmit(interpret(permachine), { let p1 = this.baseSubmit(interpret(permachine), {
action: "init_session", action: "init_session",
}).then((res) => {
// 自动调度,维持session活性
this.keepaliveSession();
}); });
return p1
}, },
asyncInit() { asyncInit() {
if (!this.online) { if (!this.online) {
@ -263,5 +346,11 @@ export const fetchStore = defineStore("fetch", {
} }
return Promise.resolve("alrealy init"); return Promise.resolve("alrealy init");
}, },
closeSession() {
return this.baseSubmit(interpret(permachine), {
action: "close_session",
sessionId: undefined,
});
},
}, },
}); });