-
-
Notifications
You must be signed in to change notification settings - Fork 690
Handle KubeBlock v5 upgrade API call for horizontal scaling #2063
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
Changes from all commits
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 | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,6 +20,7 @@ import { ApplicationBundle } from 'src/application/entities/application-bundle' | |||||||||||||||||||||||||||||||||||||||
| import * as assert from 'assert' | ||||||||||||||||||||||||||||||||||||||||
| import { extractNumber } from 'src/utils/number' | ||||||||||||||||||||||||||||||||||||||||
| import { formatK8sErrorAsJson } from 'src/utils/k8s-error' | ||||||||||||||||||||||||||||||||||||||||
| import { ServerConfig, KUBEBLOCK_V5_UPGRADE_API_TIMEOUT } from 'src/constants' | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const getDedicatedDatabaseName = (appid: string) => appid | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
@@ -142,13 +143,18 @@ export class DedicatedDatabaseService { | |||||||||||||||||||||||||||||||||||||||
| appid, | ||||||||||||||||||||||||||||||||||||||||
| 'horizontalScaling', | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (!OpsRequestManifest) { | ||||||||||||||||||||||||||||||||||||||||
| const result = await this.applyKubeBlockOpsRequestManifestForSpec( | ||||||||||||||||||||||||||||||||||||||||
| region, | ||||||||||||||||||||||||||||||||||||||||
| appid, | ||||||||||||||||||||||||||||||||||||||||
| spec, | ||||||||||||||||||||||||||||||||||||||||
| 'horizontalScaling', | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Call KubeBlock v5 compatibility API if needed | ||||||||||||||||||||||||||||||||||||||||
| await this.handleKubeBlockV5Upgrade(appid, manifest, spec.replicas) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| results.push(result) | ||||||||||||||||||||||||||||||||||||||||
| this.logger.log( | ||||||||||||||||||||||||||||||||||||||||
| `Applied horizontalScaling ops request for ${appid}: replicas=${spec.replicas}`, | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -702,4 +708,116 @@ export class DedicatedDatabaseService { | |||||||||||||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Handle KubeBlock v5 upgrade API call for horizontal scaling | ||||||||||||||||||||||||||||||||||||||||
| * This is a compatibility feature for KubeBlock v5 mongodb-5.0 clusters | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @param appid - Application ID | ||||||||||||||||||||||||||||||||||||||||
| * @param manifest - Current deployment manifest | ||||||||||||||||||||||||||||||||||||||||
| * @param replicas - Number of replicas | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| private async handleKubeBlockV5Upgrade( | ||||||||||||||||||||||||||||||||||||||||
| appid: string, | ||||||||||||||||||||||||||||||||||||||||
| manifest: KubernetesObject & { spec: any; status: any }, | ||||||||||||||||||||||||||||||||||||||||
| replicas: number, | ||||||||||||||||||||||||||||||||||||||||
| ): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||
| // Early return if not a v5 mongodb-5.0 cluster | ||||||||||||||||||||||||||||||||||||||||
| if (!this.isKubeBlockV5MongoDb(manifest)) { | ||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const url = ServerConfig.KUBEBLOCK_V5_UPGRADE_URL | ||||||||||||||||||||||||||||||||||||||||
| if (!url) { | ||||||||||||||||||||||||||||||||||||||||
| this.logger.warn( | ||||||||||||||||||||||||||||||||||||||||
| `KubeBlock v5 upgrade URL not configured (KUBEBLOCK_V5_UPGRADE_URL env var not set) for ${appid}`, | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| await this.callKubeBlockV5UpgradeAPI(appid, manifest, replicas, url) | ||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||
| this.logger.error( | ||||||||||||||||||||||||||||||||||||||||
| `Failed to call KubeBlock v5 upgrade API for ${appid}: ${error.message}`, | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| // Don't throw error, just log it as it's a compatibility feature | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Check if the manifest is a KubeBlock v5 mongodb-5.0 cluster | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| private isKubeBlockV5MongoDb( | ||||||||||||||||||||||||||||||||||||||||
| manifest: KubernetesObject & { spec: any; status: any }, | ||||||||||||||||||||||||||||||||||||||||
| ): boolean { | ||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||
| manifest?.metadata?.labels?.['clusterversion.kubeblocks.io/name'] === | ||||||||||||||||||||||||||||||||||||||||
| 'mongodb-5.0' | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Call KubeBlock v5 upgrade API with timeout control | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| private async callKubeBlockV5UpgradeAPI( | ||||||||||||||||||||||||||||||||||||||||
| appid: string, | ||||||||||||||||||||||||||||||||||||||||
| manifest: KubernetesObject & { spec: any; status: any }, | ||||||||||||||||||||||||||||||||||||||||
| replicas: number, | ||||||||||||||||||||||||||||||||||||||||
| url: string, | ||||||||||||||||||||||||||||||||||||||||
| ): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||
| const clusterName = manifest.metadata.name | ||||||||||||||||||||||||||||||||||||||||
| const namespace = manifest.metadata.namespace | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+769
to
+770
|
||||||||||||||||||||||||||||||||||||||||
| const clusterName = manifest.metadata.name | |
| const namespace = manifest.metadata.namespace | |
| const clusterName = manifest?.metadata?.name | |
| const namespace = manifest?.metadata?.namespace | |
| if (!clusterName || !namespace) { | |
| throw new Error('Invalid manifest: missing name or namespace') | |
| } |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fetch API is being used directly without any visible import. While fetch is globally available in Node.js 18+, this codebase appears to use @nestjs/axios (HttpService) for HTTP requests elsewhere in the project (e.g., in http-interceptor.service.ts, wechat-pay.service.ts). For consistency and better error handling, consider using the injected HttpService instead of the global fetch API.
Using HttpService would provide:
- Consistent error handling patterns across the codebase
- Built-in timeout support via axios configuration
- Better integration with NestJS ecosystem
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The response parsing happens before checking response.ok, which means the response body is consumed before the error check. If the response is not OK and has a large body, this could be inefficient. More importantly, if parseKubeBlockV5Response fails (e.g., malformed JSON), the error message won't include the HTTP status information.
Consider checking response.ok first, then parsing the response body only when needed:
if (!response.ok) {
const errorBody = await this.parseKubeBlockV5Response(response)
throw new Error(
`HTTP error! status: ${response.status}, statusText: ${response.statusText}, body: ${JSON.stringify(errorBody)}`
)
}
const responseData = await this.parseKubeBlockV5Response(response)| const responseData = await this.parseKubeBlockV5Response(response) | |
| if (!response.ok) { | |
| throw new Error( | |
| `HTTP error! status: ${response.status}, statusText: ${ | |
| response.statusText | |
| }, body: ${JSON.stringify(responseData)}`, | |
| ) | |
| } | |
| if (!response.ok) { | |
| const errorBody = await this.parseKubeBlockV5Response(response) | |
| throw new Error( | |
| `HTTP error! status: ${response.status}, statusText: ${ | |
| response.statusText | |
| }, body: ${JSON.stringify(errorBody)}`, | |
| ) | |
| } | |
| const responseData = await this.parseKubeBlockV5Response(response) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the AbortController aborts the request due to timeout, it will throw an
AbortError. However, this error is caught by the outer try-catch inhandleKubeBlockV5Upgrade(line 740-745) which only logserror.message. For AbortError, the message might not clearly indicate it was a timeout.Consider adding specific handling for timeout errors to provide clearer logging: