-
-
Notifications
You must be signed in to change notification settings - Fork 331
修复可用性监控加载过慢 #1186
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
修复可用性监控加载过慢 #1186
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 | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -39,15 +39,45 @@ function normalizeSql(sqlObject: unknown): string { | |||||||||||||||||||||||||||||||||
| return sqlToString(sqlObject).replace(/\s+/g, " ").trim().toLowerCase(); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| function findCteBoundary( | ||||||||||||||||||||||||||||||||||
| queryText: string, | ||||||||||||||||||||||||||||||||||
| cteName: string | ||||||||||||||||||||||||||||||||||
| ): { cteStart: number; boundaryStart: number } | null { | ||||||||||||||||||||||||||||||||||
| // cteName 先经长度/格式校验,再生成 escapedName 参与受控测试正则构造。 | ||||||||||||||||||||||||||||||||||
| if (queryText.length === 0 || cteName.length > 100 || !/^[a-z_][a-z0-9_]*$/i.test(cteName)) { | ||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const escapedName = cteName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); | ||||||||||||||||||||||||||||||||||
| const match = new RegExp(`(^|\\bwith\\s+|,\\s*)("?${escapedName}"?)\\s+as\\s*\\(`).exec( | ||||||||||||||||||||||||||||||||||
| queryText | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+47
to
+54
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. The
Suggested change
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (!match?.[2]) { | ||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||
| cteStart: match.index + match[1].length, | ||||||||||||||||||||||||||||||||||
| boundaryStart: match.index, | ||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
tesgth032 marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| function extractFinalizedRequestsSql(queryText: string): string { | ||||||||||||||||||||||||||||||||||
| const start = queryText.indexOf("finalized_requests as"); | ||||||||||||||||||||||||||||||||||
| const end = queryText.indexOf("provider_bucket_stats as"); | ||||||||||||||||||||||||||||||||||
| const start = findCteBoundary(queryText, "finalized_requests"); | ||||||||||||||||||||||||||||||||||
| const end = findCteBoundary(queryText, "provider_bucket_stats"); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (start === -1 || end === -1 || end <= start) { | ||||||||||||||||||||||||||||||||||
| throw new Error("Could not locate finalized_requests CTE in query text"); | ||||||||||||||||||||||||||||||||||
| if (!start) { | ||||||||||||||||||||||||||||||||||
| throw new Error("finalized_requests CTE not found in query text"); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| if (!end) { | ||||||||||||||||||||||||||||||||||
| throw new Error("provider_bucket_stats CTE not found in query text"); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| if (end.boundaryStart <= start.cteStart) { | ||||||||||||||||||||||||||||||||||
| throw new Error("finalized_requests CTE appears after provider_bucket_stats CTE"); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return queryText.slice(start, end); | ||||||||||||||||||||||||||||||||||
| return queryText.slice(start.cteStart, end.boundaryStart); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| describe("availability-service", () => { | ||||||||||||||||||||||||||||||||||
|
|
@@ -309,7 +339,7 @@ describe("availability-service", () => { | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const queryText = normalizeSql(executeMock.mock.calls[0]?.[0]); | ||||||||||||||||||||||||||||||||||
| const finalizedRequestsSql = extractFinalizedRequestsSql(queryText); | ||||||||||||||||||||||||||||||||||
| expect(finalizedRequestsSql).toContain("fn_is_message_request_finalized"); | ||||||||||||||||||||||||||||||||||
| expect(finalizedRequestsSql).toContain('"status_code" is not null'); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain("group by"); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain("percentile_cont(0.95)"); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain("row_number() over"); | ||||||||||||||||||||||||||||||||||
|
|
@@ -482,7 +512,7 @@ describe("availability-service", () => { | |||||||||||||||||||||||||||||||||
| const finalizedRequestsSql = extractFinalizedRequestsSql( | ||||||||||||||||||||||||||||||||||
| normalizeSql(executeMock.mock.calls[0]?.[0]) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| expect(finalizedRequestsSql).toContain("fn_is_message_request_finalized"); | ||||||||||||||||||||||||||||||||||
| expect(finalizedRequestsSql).toContain('"status_code" is not null'); | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| it("queryProviderAvailability 会保留 Gemini passthrough 终态(statusCode!=null 且 durationMs=null)", async () => { | ||||||||||||||||||||||||||||||||||
|
|
@@ -515,6 +545,7 @@ describe("availability-service", () => { | |||||||||||||||||||||||||||||||||
| const finalizedRequestsSql = extractFinalizedRequestsSql( | ||||||||||||||||||||||||||||||||||
| normalizeSql(executeMock.mock.calls[0]?.[0]) | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| expect(finalizedRequestsSql).toContain('"status_code" is not null'); | ||||||||||||||||||||||||||||||||||
| expect(finalizedRequestsSql).not.toMatch(/where .*duration_?ms.*is not null/); | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -548,7 +579,7 @@ describe("availability-service", () => { | |||||||||||||||||||||||||||||||||
| const queryText = normalizeSql(executeMock.mock.calls[0]?.[0]); | ||||||||||||||||||||||||||||||||||
| const finalizedRequestsSql = extractFinalizedRequestsSql(queryText); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| expect(finalizedRequestsSql).toContain("fn_is_message_request_finalized"); | ||||||||||||||||||||||||||||||||||
| expect(finalizedRequestsSql).toContain('"status_code" is not null'); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain("fn_compute_message_request_success_rate_outcome"); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain(`"successrateoutcome" = 'failure'`); | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
@@ -717,7 +748,7 @@ describe("availability-service", () => { | |||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const queryText = normalizeSql(executeMock.mock.calls[0]?.[0]); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain("fn_is_message_request_finalized"); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain('"status_code" is not null'); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain(">= now() - (15 * interval '1 minute')"); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain("<= now()"); | ||||||||||||||||||||||||||||||||||
| expect(queryText).toContain("count(*) filter"); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.