-
Notifications
You must be signed in to change notification settings - Fork 9
Reduce contracts and deployments loading time #4233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Changes from 5 commits
1f525e8
3e900a9
23301da
236bbbb
2cb4f99
0482f2c
3484c4c
500da01
f90894e
26d9a93
2d1bb02
91d0faf
13747a8
c62179c
3d9814c
469b79b
784df78
3796e69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,8 +6,7 @@ | |
| <span> | ||
| This might happen because the node is down or it's not reachable | ||
| <span v-if="showEncryption"> | ||
| or the deployment{{ count - items.length > 1 ? "s are" : " is" }} encrypted by another key | ||
| </span>. | ||
| or the deployment{{ count - items.length > 1 ? "s are" : " is" }} encrypted by another key </span>. | ||
| </span> | ||
| <v-tooltip location="top" text="Show failed deployments"> | ||
| <template #activator="{ props: tooltipProps }"> | ||
|
|
@@ -168,7 +167,7 @@ import { getNodeHealthColor, NodeHealth } from "@/utils/get_nodes"; | |
| import { useProfileManager } from "../stores"; | ||
| import { getGrid, updateGrid } from "../utils/grid"; | ||
| import { markAsFromAnotherClient } from "../utils/helpers"; | ||
| import { type K8S, type LoadedDeployments, loadK8s, mergeLoadedDeployments } from "../utils/load_deployment"; | ||
| import { loadK8s, mergeLoadedDeployments } from "../utils/load_deployment"; | ||
| const profileManager = useProfileManager(); | ||
| const showDialog = ref(false); | ||
| const showEncryption = ref(false); | ||
|
|
@@ -188,35 +187,82 @@ const loading = ref(false); | |
|
|
||
| onMounted(loadDeployments); | ||
| async function loadDeployments() { | ||
| const start = performance.now(); | ||
| items.value = []; | ||
| loading.value = true; | ||
| const grid = await getGrid(profileManager.profile!, props.projectName); | ||
| const chunk1 = await loadK8s(grid!); | ||
| const chunk2 = await loadK8s(updateGrid(grid!, { projectName: props.projectName.toLowerCase() })); | ||
| let chunk3: LoadedDeployments<K8S> = { count: 0, items: [], failedDeployments: [] }; | ||
|
|
||
| if (showAllDeployments.value) { | ||
| chunk3 = await loadK8s(updateGrid(grid!, { projectName: "" })); | ||
| chunk3.items = chunk3.items.map(i => { | ||
| return !i.projectName || i.projectName === "Kubernetes" ? markAsFromAnotherClient(i) : i; | ||
| try { | ||
| const grid = await getGrid(profileManager.profile!, props.projectName); | ||
| if (!grid) { | ||
| loading.value = false; | ||
0oM4R marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return; | ||
| } | ||
| const [chunk1, chunk2, chunk3] = await Promise.all([ | ||
| loadK8s(grid), | ||
| loadK8s(updateGrid(grid, { projectName: props.projectName.toLowerCase() })), | ||
| showAllDeployments.value | ||
| ? loadK8s(updateGrid(grid, { projectName: "" })) | ||
| : Promise.resolve({ count: 0, items: [], failedDeployments: [] }), | ||
| ]); | ||
0oM4R marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (chunk3.items) { | ||
| chunk3.items = chunk3.items.map(i => { | ||
| return !i.projectName || i.projectName === "Kubernetes" ? markAsFromAnotherClient(i) : i; | ||
| }); | ||
| } | ||
| const clusters = mergeLoadedDeployments(chunk1, chunk2, chunk3); | ||
| failedDeployments.value = clusters.failedDeployments; | ||
| count.value = clusters.count; | ||
| items.value = clusters.items.map(item => { | ||
| const master = item.masters[0]; | ||
| const publicIP = master.publicIP?.ip; | ||
| return { | ||
| ...item, | ||
| name: item.deploymentName, | ||
| ipv4: publicIP ? publicIP.split("/")?.[0] || publicIP : "-", | ||
| ipv6: master.publicIP?.ip6?.replace(/\/64$/, "") || "-", | ||
| planetary: master.planetary || "-", | ||
| workersLength: item.workers.length, | ||
| billing: undefined, | ||
| wireguard: undefined, | ||
| detailsLoading: false, | ||
| }; | ||
| }); | ||
|
|
||
| setTimeout(() => { | ||
| items.value.forEach(item => fetchClusterDetails(item)); | ||
| }, 0); | ||
|
||
| } catch (error) { | ||
| console.error("Error loading deployments:", error); | ||
| items.value = []; | ||
| count.value = 0; | ||
| failedDeployments.value = []; | ||
| } finally { | ||
| loading.value = false; | ||
| const end = performance.now(); | ||
| console.log(`Time taken: ${(end - start) / 1000} seconds`); | ||
| } | ||
| } | ||
|
|
||
| const clusters = mergeLoadedDeployments(chunk1, chunk2, chunk3); | ||
| failedDeployments.value = clusters.failedDeployments; | ||
|
|
||
| count.value = clusters.count; | ||
| items.value = clusters.items.map((item: any) => { | ||
| item.name = item.deploymentName; | ||
| item.ipv4 = item.masters[0].publicIP?.ip?.split("/")?.[0] || item.masters[0].publicIP?.ip || "-"; | ||
| item.ipv6 = item.masters[0].publicIP?.ip6.replace(/\/64$/, "") || "-"; | ||
| item.planetary = item.masters[0].planetary || "-"; | ||
| item.workersLength = item.workers.length; | ||
| item.billing = item.masters[0].billing; | ||
| item.created = item.masters[0].created; | ||
| return item; | ||
| }); | ||
| loading.value = false; | ||
| async function fetchClusterDetails(item: any) { | ||
| if (item.detailsLoading || (item.billing !== undefined && item.wireguard !== undefined)) return; | ||
0oM4R marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| item.detailsLoading = true; | ||
| try { | ||
| const grid = await getGrid(profileManager.profile!, item.projectName || props.projectName); | ||
| if (!grid) { | ||
| item.detailsLoading = false; | ||
| return; | ||
| } | ||
| const consumption = await grid.contracts.getConsumption({ id: item.masters[0].contractId }).catch(() => undefined); | ||
|
||
| item.billing = consumption ? consumption.amountBilled : "No Data Available"; | ||
| item.wireguard = await grid.networks | ||
|
||
| .getWireGuardConfigs({ | ||
| name: item.masters[0].interfaces[0].network, | ||
| ipRange: item.masters[0].interfaces[0].ip, | ||
| }) | ||
| .then(res => res[0]) | ||
| .catch(() => undefined); | ||
| } finally { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a catch block; to at least log the errors
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| item.detailsLoading = false; | ||
| } | ||
| } | ||
|
|
||
| defineExpose({ loadDeployments }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,33 +1,18 @@ | ||
| <template> | ||
| <div> | ||
| <v-alert | ||
| v-if="errorMessage" | ||
| type="error" | ||
| variant="tonal" | ||
| > | ||
| <v-alert v-if="errorMessage" type="error" variant="tonal"> | ||
| {{ errorMessage }} | ||
| </v-alert> | ||
| <v-alert | ||
| v-if="!loading && count && items.length < count" | ||
| type="warning" | ||
| variant="tonal" | ||
| > | ||
| <v-alert v-if="!loading && count && items.length < count" type="warning" variant="tonal"> | ||
| Failed to load <strong>{{ count - items.length }}</strong> deployment{{ count - items.length > 1 ? "s" : "" }}. | ||
|
|
||
| <span> | ||
| This might happen because the node is down or it's not reachable | ||
| <span v-if="showEncryption">or the deployment{{ count - items.length > 1 ? "s are" : " is" }} encrypted by another key</span>. | ||
| </span> | ||
| <v-tooltip | ||
| location="top" | ||
| text="Show failed deployments" | ||
| > | ||
| <v-tooltip location="top" text="Show failed deployments"> | ||
| <template #activator="{ props: slotProps }"> | ||
| <v-icon | ||
| v-bind="slotProps" | ||
| class="custom-icon" | ||
| @click="showDialog = true" | ||
| > | ||
| <v-icon v-bind="slotProps" class="custom-icon" @click="showDialog = true"> | ||
| mdi-file-document-refresh-outline | ||
| </v-icon> | ||
| </template> | ||
|
|
@@ -41,15 +26,10 @@ | |
| attach="#modals" | ||
| > | ||
| <v-card> | ||
| <v-card-title style="font-weight: bold"> | ||
| Failed Deployments | ||
| </v-card-title> | ||
| <v-card-title style="font-weight: bold"> Failed Deployments </v-card-title> | ||
| <v-divider color="#FFCC00" /> | ||
| <v-card-text> | ||
| <v-alert | ||
| type="error" | ||
| variant="tonal" | ||
| > | ||
| <v-alert type="error" variant="tonal"> | ||
| Failed to load | ||
| <strong>{{ count - items.length }}</strong> deployment{{ count - items.length > 1 ? "s" : "" }}. | ||
|
|
||
|
|
@@ -58,23 +38,14 @@ | |
| <span v-if="showEncryption">or the deployment{{ count - items.length > 1 ? "s are" : " is" }} encrypted by another key</span>. | ||
| </span> | ||
| </v-alert> | ||
| <v-list | ||
| :items="failedDeploymentList" | ||
| item-props | ||
| lines="three" | ||
| > | ||
| <v-list :items="failedDeploymentList" item-props lines="three"> | ||
| <template #subtitle="{ subtitle }"> | ||
| <div v-html="subtitle" /> | ||
| </template> | ||
| </v-list> | ||
| </v-card-text> | ||
| <v-card-actions class="justify-end my-1 mr-2"> | ||
| <v-btn | ||
| color="anchor" | ||
| @click="showDialog = false" | ||
| > | ||
| Close | ||
| </v-btn> | ||
| <v-btn color="anchor" @click="showDialog = false"> Close </v-btn> | ||
| </v-card-actions> | ||
| </v-card> | ||
| </v-dialog> | ||
|
|
@@ -139,10 +110,7 @@ | |
| </template> | ||
|
|
||
| <template #[`item.flist`]="{ item }"> | ||
| <v-tooltip | ||
| :text="item.flist" | ||
| location="bottom right" | ||
| > | ||
| <v-tooltip :text="item.flist" location="bottom right"> | ||
| <template #activator="{ props: slotProps }"> | ||
| <p v-bind="slotProps"> | ||
| {{ renameFlist(item.flist) }} | ||
|
|
@@ -158,40 +126,18 @@ | |
| {{ toHumanDate(item.created) }} | ||
| </template> | ||
| <template #[`item.actions`]="{ item }"> | ||
| <v-chip | ||
| v-if="deleting && ($props.modelValue || []).includes(item)" | ||
| color="error" | ||
| > | ||
| Deleting... | ||
| </v-chip> | ||
| <v-btn-group | ||
| v-else | ||
| variant="tonal" | ||
| > | ||
| <slot | ||
| :name="projectName + '-actions'" | ||
| :item="item" | ||
| :update="updateItem" | ||
| /> | ||
| <v-chip v-if="deleting && ($props.modelValue || []).includes(item)" color="error"> Deleting... </v-chip> | ||
| <v-btn-group v-else variant="tonal"> | ||
| <slot :name="projectName + '-actions'" :item="item" :update="updateItem" /> | ||
| </v-btn-group> | ||
| </template> | ||
|
|
||
| <template #[`item.status`]="{ item }"> | ||
| <v-chip :color="getNodeHealthColor(item.status as string).color"> | ||
| <v-tooltip | ||
| v-if="item.status == NodeHealth.Error" | ||
| activator="parent" | ||
| location="top" | ||
| > | ||
| {{ | ||
| item.message | ||
| }} | ||
| <v-tooltip v-if="item.status == NodeHealth.Error" activator="parent" location="top"> | ||
| {{ item.message }} | ||
| </v-tooltip> | ||
| <v-tooltip | ||
| v-if="item.status == NodeHealth.Paused" | ||
| activator="parent" | ||
| location="top" | ||
| > | ||
| <v-tooltip v-if="item.status == NodeHealth.Paused" activator="parent" location="top"> | ||
| The deployment contract is in grace period | ||
| </v-tooltip> | ||
| <span class="text-uppercase"> | ||
|
|
@@ -201,20 +147,10 @@ | |
| </template> | ||
| <template #[`item.health`]="{ item }"> | ||
| <v-chip :color="getNodeHealthColor(item[0].workloads[0].result.state as string).color"> | ||
| <v-tooltip | ||
| v-if="item[0].workloads[0].result.state == NodeHealth.Error" | ||
| activator="parent" | ||
| location="top" | ||
| > | ||
| {{ | ||
| item.message | ||
| }} | ||
| <v-tooltip v-if="item[0].workloads[0].result.state == NodeHealth.Error" activator="parent" location="top"> | ||
| {{ item.message }} | ||
| </v-tooltip> | ||
| <v-tooltip | ||
| v-if="item[0].workloads[0].result.state == NodeHealth.Paused" | ||
| activator="parent" | ||
| location="top" | ||
| > | ||
| <v-tooltip v-if="item[0].workloads[0].result.state == NodeHealth.Paused" activator="parent" location="top"> | ||
| The deployment contract is in grace period | ||
| </v-tooltip> | ||
| <span class="text-uppercase"> | ||
|
|
@@ -224,10 +160,7 @@ | |
| </template> | ||
|
|
||
| <template #no-data-text> | ||
| <div | ||
| v-if="failedDeploymentList.length > 0" | ||
| class="text-center" | ||
| > | ||
| <div v-if="failedDeploymentList.length > 0" class="text-center"> | ||
| <p v-text="'Couldn\'t load any of your ' + projectTitle + ' deployments.'" /> | ||
| <VBtn | ||
| class="mt-4" | ||
|
|
@@ -238,10 +171,7 @@ | |
| @click="loadDeployments" | ||
| /> | ||
| </div> | ||
| <p | ||
| v-else | ||
| v-text="'No ' + projectTitle + ' deployments found on this account.'" | ||
| /> | ||
| <p v-else v-text="'No ' + projectTitle + ' deployments found on this account.'" /> | ||
| </template> | ||
| </ListTable> | ||
| </div> | ||
|
|
@@ -255,7 +185,7 @@ import { getNodeHealthColor, NodeHealth } from "@/utils/get_nodes"; | |
| import { useProfileManager } from "../stores"; | ||
| import { getGrid, updateGrid } from "../utils/grid"; | ||
| import { markAsFromAnotherClient } from "../utils/helpers"; | ||
| import { type LoadedDeployments, loadVms, mergeLoadedDeployments } from "../utils/load_deployment"; | ||
| import { loadVms, mergeLoadedDeployments } from "../utils/load_deployment"; | ||
|
|
||
| const profileManager = useProfileManager(); | ||
|
|
||
|
|
@@ -303,6 +233,7 @@ async function loadDomains() { | |
| } | ||
|
|
||
| async function loadDeployments() { | ||
| const start = performance.now(); | ||
| if (props.projectName.toLowerCase() === ProjectName.Domains.toLowerCase()) { | ||
| return loadDomains(); | ||
| } | ||
|
|
@@ -313,27 +244,31 @@ async function loadDeployments() { | |
| loading.value = true; | ||
| const grid = await getGrid(profileManager.profile!, props.projectName); | ||
| try { | ||
| const chunk1 = await loadVms(grid!); | ||
| if (chunk1.count > 0 && migrateGateways) { | ||
| await migrateModule(grid!.gateway); | ||
| } | ||
| const results = await Promise.allSettled([ | ||
| loadVms(grid!), | ||
| loadVms(updateGrid(grid!, { projectName: props.projectName.toLowerCase() })), | ||
| showAllDeployments.value && props.projectName.toLowerCase() === ProjectName.VM.toLowerCase() | ||
|
||
| ? loadVms(updateGrid(grid!, { projectName: "" })) | ||
| : Promise.resolve({ count: 0, items: [], failedDeployments: [] }), | ||
| ]); | ||
| const [chunk1, chunk2, chunk3] = results.map((result, index) => { | ||
| if (result.status === "fulfilled") { | ||
| return result.value; | ||
| } else { | ||
| console.warn(`Failed to load VM chunk ${index + 1}:`, result.reason); | ||
| return { count: 0, items: [], failedDeployments: [] }; | ||
| } | ||
| }); | ||
|
|
||
| const chunk2 = await loadVms(updateGrid(grid!, { projectName: props.projectName.toLowerCase() })); | ||
| if (chunk2.count > 0 && migrateGateways) { | ||
| await migrateModule(grid!.gateway); | ||
| if (migrateGateways) { | ||
| await Promise.all([ | ||
| chunk1.count > 0 && migrateModule(grid!.gateway), | ||
| chunk2.count > 0 && migrateModule(grid!.gateway), | ||
| chunk3.count > 0 && migrateModule(grid!.gateway), | ||
| ]); | ||
0oM4R marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| let chunk3: LoadedDeployments<any[]> = { count: 0, items: [], failedDeployments: [] }; | ||
| if (showAllDeployments.value) { | ||
| chunk3 = | ||
| props.projectName.toLowerCase() === ProjectName.VM.toLowerCase() | ||
| ? await loadVms(updateGrid(grid!, { projectName: "" })) | ||
| : { count: 0, items: [], failedDeployments: [] }; | ||
|
|
||
| if (chunk3.count > 0 && migrateGateways) { | ||
| await migrateModule(grid!.gateway); | ||
| } | ||
|
|
||
| if (chunk3.items) { | ||
| chunk3.items = chunk3.items.map(markAsFromAnotherClient); | ||
| } | ||
|
|
||
|
|
@@ -346,8 +281,8 @@ async function loadDeployments() { | |
| } finally { | ||
| loading.value = false; | ||
| } | ||
|
|
||
| loading.value = false; | ||
| const end = performance.now(); | ||
| console.log(`Time taken: ${(end - start) / 1000} seconds`); | ||
| } | ||
|
|
||
| const filteredHeaders = computed(() => { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.