forge-sql-orm 2.1.9 → 2.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -254
- package/dist/ForgeSQLORM.js +3238 -3231
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +3236 -3229
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +70 -16
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +95 -16
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/core/SystemTables.d.ts +82 -82
- package/dist/lib/drizzle/extensions/additionalActions.d.ts +30 -6
- package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
- package/dist/utils/cacheUtils.d.ts.map +1 -1
- package/dist/utils/forgeDriver.d.ts.map +1 -1
- package/dist/utils/forgeDriverProxy.d.ts +6 -2
- package/dist/utils/forgeDriverProxy.d.ts.map +1 -1
- package/dist/utils/metadataContextUtils.d.ts +5 -2
- package/dist/utils/metadataContextUtils.d.ts.map +1 -1
- package/dist/utils/sqlUtils.d.ts +72 -1
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/webtriggers/index.d.ts +1 -1
- package/dist/webtriggers/index.d.ts.map +1 -1
- package/dist/webtriggers/slowQuerySchedulerTrigger.d.ts +67 -0
- package/dist/webtriggers/slowQuerySchedulerTrigger.d.ts.map +1 -0
- package/package.json +14 -14
- package/src/core/ForgeSQLORM.ts +165 -34
- package/src/core/ForgeSQLQueryBuilder.ts +118 -19
- package/src/core/SystemTables.ts +1 -1
- package/src/lib/drizzle/extensions/additionalActions.ts +231 -18
- package/src/utils/cacheUtils.ts +3 -1
- package/src/utils/forgeDriver.ts +10 -42
- package/src/utils/forgeDriverProxy.ts +58 -6
- package/src/utils/metadataContextUtils.ts +21 -6
- package/src/utils/sqlUtils.ts +229 -2
- package/src/webtriggers/index.ts +1 -1
- package/src/webtriggers/slowQuerySchedulerTrigger.ts +82 -0
- package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts +0 -114
- package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts.map +0 -1
- package/src/webtriggers/topSlowestStatementLastHourTrigger.ts +0 -563
package/src/utils/sqlUtils.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
and,
|
|
3
|
+
AnyColumn,
|
|
4
|
+
Column,
|
|
5
|
+
gte,
|
|
6
|
+
ilike,
|
|
7
|
+
isNotNull,
|
|
8
|
+
isTable,
|
|
9
|
+
ne,
|
|
10
|
+
not,
|
|
11
|
+
notInArray,
|
|
12
|
+
SQL,
|
|
13
|
+
sql,
|
|
14
|
+
StringChunk,
|
|
15
|
+
} from "drizzle-orm";
|
|
2
16
|
import { AnyMySqlTable, MySqlCustomColumn } from "drizzle-orm/mysql-core/index";
|
|
3
17
|
import { DateTime } from "luxon";
|
|
4
18
|
import { PrimaryKeyBuilder } from "drizzle-orm/mysql-core/primary-keys";
|
|
@@ -6,9 +20,16 @@ import { AnyIndexBuilder } from "drizzle-orm/mysql-core/indexes";
|
|
|
6
20
|
import { CheckBuilder } from "drizzle-orm/mysql-core/checks";
|
|
7
21
|
import { ForeignKeyBuilder } from "drizzle-orm/mysql-core/foreign-keys";
|
|
8
22
|
import { UniqueConstraintBuilder } from "drizzle-orm/mysql-core/unique-constraint";
|
|
9
|
-
import
|
|
23
|
+
import {
|
|
24
|
+
SelectedFields
|
|
25
|
+
} from "drizzle-orm/mysql-core/query-builders/select.types";
|
|
10
26
|
import { MySqlTable } from "drizzle-orm/mysql-core";
|
|
11
27
|
import { isSQLWrapper } from "drizzle-orm/sql/sql";
|
|
28
|
+
import {clusterStatementsSummary, slowQuery} from "../core/SystemTables";
|
|
29
|
+
import { ForgeSqlOperation } from "../core/ForgeSQLQueryBuilder";
|
|
30
|
+
import { ColumnDataType} from "drizzle-orm/column-builder";
|
|
31
|
+
import {AnyMySqlColumn} from "drizzle-orm/mysql-core/columns/common";
|
|
32
|
+
import type {ColumnBaseConfig} from "drizzle-orm/column";
|
|
12
33
|
|
|
13
34
|
/**
|
|
14
35
|
* Interface representing table metadata information
|
|
@@ -536,3 +557,209 @@ export function formatLimitOffset(limitOrOffset: number): number {
|
|
|
536
557
|
export function nextVal(sequenceName: string): number {
|
|
537
558
|
return sql.raw(`NEXTVAL(${sequenceName})`) as unknown as number;
|
|
538
559
|
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Analyzes and prints query performance data from CLUSTER_STATEMENTS_SUMMARY table.
|
|
563
|
+
*
|
|
564
|
+
* This function queries the CLUSTER_STATEMENTS_SUMMARY table to find queries that were executed
|
|
565
|
+
* within the specified time window and prints detailed performance information including:
|
|
566
|
+
* - SQL query text
|
|
567
|
+
* - Memory usage (average and max in MB)
|
|
568
|
+
* - Execution time (average in ms)
|
|
569
|
+
* - Number of executions
|
|
570
|
+
* - Execution plan
|
|
571
|
+
*
|
|
572
|
+
* @param forgeSQLORM - The ForgeSQL operation instance for database access
|
|
573
|
+
* @param timeDiffMs - Time window in milliseconds to look back for queries (e.g., 1500 for last 1.5 seconds)
|
|
574
|
+
* @param timeout - Optional timeout in milliseconds for the query execution (defaults to 1500ms)
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```typescript
|
|
578
|
+
* // Analyze queries from the last 2 seconds
|
|
579
|
+
* await printQueriesWithPlan(forgeSQLORM, 2000);
|
|
580
|
+
*
|
|
581
|
+
* // Analyze queries with custom timeout
|
|
582
|
+
* await printQueriesWithPlan(forgeSQLORM, 1000, 3000);
|
|
583
|
+
* ```
|
|
584
|
+
*
|
|
585
|
+
* @throws Does not throw - errors are logged to console.debug instead
|
|
586
|
+
*/
|
|
587
|
+
export async function printQueriesWithPlan(
|
|
588
|
+
forgeSQLORM: ForgeSqlOperation,
|
|
589
|
+
timeDiffMs: number,
|
|
590
|
+
timeout?: number,
|
|
591
|
+
) {
|
|
592
|
+
try {
|
|
593
|
+
const statementsTable = clusterStatementsSummary;
|
|
594
|
+
const timeoutMs = timeout ?? 3000;
|
|
595
|
+
const results = await withTimeout(
|
|
596
|
+
forgeSQLORM
|
|
597
|
+
.getDrizzleQueryBuilder()
|
|
598
|
+
.select({
|
|
599
|
+
digestText: withTidbHint(statementsTable.digestText),
|
|
600
|
+
avgLatency: statementsTable.avgLatency,
|
|
601
|
+
avgMem: statementsTable.avgMem,
|
|
602
|
+
execCount: statementsTable.execCount,
|
|
603
|
+
plan: statementsTable.plan,
|
|
604
|
+
stmtType: statementsTable.stmtType,
|
|
605
|
+
})
|
|
606
|
+
.from(statementsTable)
|
|
607
|
+
.where(
|
|
608
|
+
and(
|
|
609
|
+
isNotNull(statementsTable.digest),
|
|
610
|
+
not(ilike(statementsTable.digestText, "%information_schema%")),
|
|
611
|
+
notInArray(statementsTable.stmtType, ["Use", "Set", "Show","Commit","Rollback", "Begin"]),
|
|
612
|
+
gte(
|
|
613
|
+
statementsTable.lastSeen,
|
|
614
|
+
sql`DATE_SUB
|
|
615
|
+
(NOW(), INTERVAL
|
|
616
|
+
${timeDiffMs * 1000}
|
|
617
|
+
MICROSECOND
|
|
618
|
+
)`,
|
|
619
|
+
),
|
|
620
|
+
),
|
|
621
|
+
),
|
|
622
|
+
`Timeout ${timeoutMs}ms in printQueriesWithPlan - transient timeouts are usually fine; repeated timeouts mean this diagnostic query is consistently slow and should be investigated`
|
|
623
|
+
,
|
|
624
|
+
timeoutMs+200,
|
|
625
|
+
);
|
|
626
|
+
|
|
627
|
+
results.forEach((result) => {
|
|
628
|
+
// Average execution time (convert from nanoseconds to milliseconds)
|
|
629
|
+
const avgTimeMs = Number(result.avgLatency) / 1_000_000;
|
|
630
|
+
const avgMemMB = Number(result.avgMem) / 1_000_000;
|
|
631
|
+
|
|
632
|
+
// 1. Query info: SQL, memory, time, executions
|
|
633
|
+
// eslint-disable-next-line no-console
|
|
634
|
+
console.warn(
|
|
635
|
+
`SQL: ${result.digestText} | Memory: ${avgMemMB.toFixed(2)} MB | Time: ${avgTimeMs.toFixed(2)} ms | stmtType: ${result.stmtType} | Executions: ${result.execCount}\n Plan:${result.plan}`,
|
|
636
|
+
);
|
|
637
|
+
});
|
|
638
|
+
} catch (error) {
|
|
639
|
+
// eslint-disable-next-line no-console
|
|
640
|
+
console.debug(
|
|
641
|
+
`Error occurred while retrieving query execution plan: ${error instanceof Error ? error.message : "Unknown error"}. Try again after some time`,
|
|
642
|
+
error,
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
const SESSION_ALIAS_NAME_ORM = 'orm';
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Analyzes and logs slow queries from the last specified number of hours.
|
|
651
|
+
*
|
|
652
|
+
* This function queries the slow query system table to find queries that were executed
|
|
653
|
+
* within the specified time window and logs detailed performance information including:
|
|
654
|
+
* - SQL query text
|
|
655
|
+
* - Maximum memory usage (in MB)
|
|
656
|
+
* - Query execution time (in ms)
|
|
657
|
+
* - Execution count
|
|
658
|
+
* - Execution plan
|
|
659
|
+
*
|
|
660
|
+
* @param forgeSQLORM - The ForgeSQL operation instance for database access
|
|
661
|
+
* @param hours - Number of hours to look back for slow queries (e.g., 1 for last hour, 24 for last day)
|
|
662
|
+
* @param timeout - Optional timeout in milliseconds for the query execution (defaults to 1500ms)
|
|
663
|
+
*
|
|
664
|
+
* @example
|
|
665
|
+
* ```typescript
|
|
666
|
+
* // Analyze slow queries from the last hour
|
|
667
|
+
* await slowQueryPerHours(forgeSQLORM, 1);
|
|
668
|
+
*
|
|
669
|
+
* // Analyze slow queries from the last 24 hours with custom timeout
|
|
670
|
+
* await slowQueryPerHours(forgeSQLORM, 24, 3000);
|
|
671
|
+
*
|
|
672
|
+
* // Analyze slow queries from the last 6 hours
|
|
673
|
+
* await slowQueryPerHours(forgeSQLORM, 6);
|
|
674
|
+
* ```
|
|
675
|
+
*
|
|
676
|
+
* @throws Does not throw - errors are logged to console.debug instead
|
|
677
|
+
*/
|
|
678
|
+
export async function slowQueryPerHours(forgeSQLORM: ForgeSqlOperation, hours:number, timeout?: number) {
|
|
679
|
+
try {
|
|
680
|
+
const timeoutMs = timeout ?? 1500;
|
|
681
|
+
const results = await withTimeout(
|
|
682
|
+
forgeSQLORM
|
|
683
|
+
.getDrizzleQueryBuilder()
|
|
684
|
+
.select({
|
|
685
|
+
query: withTidbHint(slowQuery.query),
|
|
686
|
+
queryTime: slowQuery.queryTime,
|
|
687
|
+
memMax: slowQuery.memMax,
|
|
688
|
+
plan: slowQuery.plan,
|
|
689
|
+
})
|
|
690
|
+
.from(slowQuery)
|
|
691
|
+
.where(
|
|
692
|
+
and(
|
|
693
|
+
isNotNull(slowQuery.digest),
|
|
694
|
+
ne(slowQuery.sessionAlias, SESSION_ALIAS_NAME_ORM),
|
|
695
|
+
gte(
|
|
696
|
+
slowQuery.time,
|
|
697
|
+
sql`DATE_SUB
|
|
698
|
+
(NOW(), INTERVAL
|
|
699
|
+
${hours}
|
|
700
|
+
HOUR
|
|
701
|
+
)`,
|
|
702
|
+
),
|
|
703
|
+
),
|
|
704
|
+
),
|
|
705
|
+
`Timeout ${timeoutMs}ms in slowQueryPerHours - transient timeouts are usually fine; repeated timeouts mean this diagnostic query is consistently slow and should be investigated`,
|
|
706
|
+
timeoutMs,
|
|
707
|
+
);
|
|
708
|
+
const response:string[] =[]
|
|
709
|
+
results.forEach((result) => {
|
|
710
|
+
// Convert memory from bytes to MB and handle null values
|
|
711
|
+
const memMaxMB = result.memMax ? Number(result.memMax) / 1_000_000 : 0;
|
|
712
|
+
|
|
713
|
+
const message = `Found SlowQuery SQL: ${result.query} | Memory: ${memMaxMB.toFixed(2)} MB | Time: ${result.queryTime} ms\n Plan:${result.plan}`;
|
|
714
|
+
response.push(message);
|
|
715
|
+
// 1. Query info: SQL, memory, time, executions
|
|
716
|
+
// eslint-disable-next-line no-console
|
|
717
|
+
console.warn(
|
|
718
|
+
message,
|
|
719
|
+
);
|
|
720
|
+
});
|
|
721
|
+
return response;
|
|
722
|
+
} catch (error) {
|
|
723
|
+
// eslint-disable-next-line no-console
|
|
724
|
+
console.debug(
|
|
725
|
+
`Error occurred while retrieving query execution plan: ${error instanceof Error ? error.message : "Unknown error"}. Try again after some time`,
|
|
726
|
+
error,
|
|
727
|
+
);
|
|
728
|
+
return [`Error occurred while retrieving query execution plan: ${error instanceof Error ? error.message : "Unknown error"}`]
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Executes a promise with a timeout.
|
|
734
|
+
*
|
|
735
|
+
* @param promise - The promise to execute
|
|
736
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
737
|
+
* @returns Promise that resolves with the result or rejects on timeout
|
|
738
|
+
* @throws {Error} When the operation times out
|
|
739
|
+
*/
|
|
740
|
+
export async function withTimeout<T>(promise: Promise<T>, message: string, timeoutMs: number): Promise<T> {
|
|
741
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
742
|
+
|
|
743
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
744
|
+
timeoutId = setTimeout(() => {
|
|
745
|
+
reject(
|
|
746
|
+
new Error(message),
|
|
747
|
+
);
|
|
748
|
+
}, timeoutMs);
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
try {
|
|
752
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
753
|
+
} finally {
|
|
754
|
+
if (timeoutId) {
|
|
755
|
+
clearTimeout(timeoutId);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
export function withTidbHint<TDataType extends ColumnDataType, TPartial extends Partial<ColumnBaseConfig<TDataType, string>>>(column: AnyMySqlColumn<TPartial>): AnyMySqlColumn<TPartial> {
|
|
761
|
+
// We lie a bit to TypeScript here: at runtime this is a new SQL fragment,
|
|
762
|
+
// but returning TExpr keeps the column type info in downstream inference.
|
|
763
|
+
return sql`/*+ SET_VAR(tidb_session_alias=${sql.raw(`${SESSION_ALIAS_NAME_ORM}`)}) */ ${column}` as unknown as AnyMySqlColumn<TPartial>;
|
|
764
|
+
}
|
|
765
|
+
|
package/src/webtriggers/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ export * from "./applyMigrationsWebTrigger";
|
|
|
3
3
|
export * from "./fetchSchemaWebTrigger";
|
|
4
4
|
export * from "./dropTablesMigrationWebTrigger";
|
|
5
5
|
export * from "./clearCacheSchedulerTrigger";
|
|
6
|
-
export * from "./
|
|
6
|
+
export * from "./slowQuerySchedulerTrigger";
|
|
7
7
|
|
|
8
8
|
export interface TriggerResponse<BODY> {
|
|
9
9
|
body?: BODY;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {getHttpResponse, TriggerResponse} from "./index";
|
|
2
|
+
import {slowQueryPerHours} from "../utils/sqlUtils";
|
|
3
|
+
import {ForgeSqlOperation} from "../core/ForgeSQLQueryBuilder";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Scheduler trigger for analyzing slow queries from the last specified number of hours.
|
|
7
|
+
*
|
|
8
|
+
* This trigger analyzes slow queries from TiDB's slow query log system table and provides
|
|
9
|
+
* detailed performance information including SQL query text, memory usage, execution time,
|
|
10
|
+
* and execution plans. It's designed to be used as a scheduled trigger in Atlassian Forge
|
|
11
|
+
* to monitor query performance over time.
|
|
12
|
+
*
|
|
13
|
+
* The function queries the slow query system table to find queries executed within the
|
|
14
|
+
* specified time window and logs detailed performance information to the console. Results
|
|
15
|
+
* are limited to the top 50 slow queries to prevent excessive output.
|
|
16
|
+
*
|
|
17
|
+
* @param forgeSQLORM - The ForgeSQL operation instance for database access
|
|
18
|
+
* @param options - Configuration options for the slow query analysis
|
|
19
|
+
* @param options.hours - Number of hours to look back for slow queries (default: 1)
|
|
20
|
+
* @param options.timeout - Timeout in milliseconds for the query execution (default: 2000ms)
|
|
21
|
+
*
|
|
22
|
+
* @returns Promise<TriggerResponse<string>> - HTTP response with JSON stringified query results or error message
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import ForgeSQL, { slowQuerySchedulerTrigger } from "forge-sql-orm";
|
|
27
|
+
*
|
|
28
|
+
* const forgeSQL = new ForgeSQL();
|
|
29
|
+
*
|
|
30
|
+
* // Basic usage with default options (1 hour, 2000ms timeout)
|
|
31
|
+
* export const slowQueryTrigger = () =>
|
|
32
|
+
* slowQuerySchedulerTrigger(forgeSQL, { hours: 1, timeout: 2000 });
|
|
33
|
+
*
|
|
34
|
+
* // Analyze slow queries from the last 6 hours with extended timeout
|
|
35
|
+
* export const sixHourSlowQueryTrigger = () =>
|
|
36
|
+
* slowQuerySchedulerTrigger(forgeSQL, { hours: 6, timeout: 5000 });
|
|
37
|
+
*
|
|
38
|
+
* // Analyze slow queries from the last 24 hours
|
|
39
|
+
* export const dailySlowQueryTrigger = () =>
|
|
40
|
+
* slowQuerySchedulerTrigger(forgeSQL, { hours: 24, timeout: 3000 });
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```yaml
|
|
45
|
+
* # manifest.yml configuration
|
|
46
|
+
* scheduledTrigger:
|
|
47
|
+
* - key: slow-query-trigger
|
|
48
|
+
* function: slowQueryTrigger
|
|
49
|
+
* interval: hour
|
|
50
|
+
*
|
|
51
|
+
* function:
|
|
52
|
+
* - key: slowQueryTrigger
|
|
53
|
+
* handler: index.slowQueryTrigger
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* - Results are automatically logged to the Forge Developer Console via `console.warn()`
|
|
58
|
+
* - The function returns up to 50 slow queries to prevent excessive logging
|
|
59
|
+
* - Transient timeouts are usually fine; repeated timeouts indicate the diagnostic query itself is slow
|
|
60
|
+
* - This trigger is best used with hourly intervals to catch slow queries in a timely manner
|
|
61
|
+
* - Error responses return HTTP 500 with error details
|
|
62
|
+
*
|
|
63
|
+
* @see {@link slowQueryPerHours} - The underlying function that performs the actual query analysis
|
|
64
|
+
*/
|
|
65
|
+
export async function slowQuerySchedulerTrigger(forgeSQLORM: ForgeSqlOperation, options: {
|
|
66
|
+
hours: number,
|
|
67
|
+
timeout: number
|
|
68
|
+
}): Promise<TriggerResponse<string>> {
|
|
69
|
+
try {
|
|
70
|
+
return getHttpResponse<string>(200, JSON.stringify(await slowQueryPerHours(forgeSQLORM, options?.hours ?? 1, options?.timeout ?? 3000)));
|
|
71
|
+
} catch (error: any) {
|
|
72
|
+
const errorMessage =
|
|
73
|
+
error?.debug?.sqlMessage ??
|
|
74
|
+
error?.debug?.message ??
|
|
75
|
+
error.message ??
|
|
76
|
+
"Unknown error occurred";
|
|
77
|
+
// eslint-disable-next-line no-console
|
|
78
|
+
console.error(errorMessage);
|
|
79
|
+
return getHttpResponse<string>(500, errorMessage);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { ForgeSqlOperation } from "../core/ForgeSQLQueryBuilder";
|
|
2
|
-
import { OperationType } from "../utils/requestTypeContextUtils";
|
|
3
|
-
interface TriggerOptions {
|
|
4
|
-
warnThresholdMs?: number;
|
|
5
|
-
memoryThresholdBytes?: number;
|
|
6
|
-
showPlan?: boolean;
|
|
7
|
-
operationType?: OperationType;
|
|
8
|
-
topN?: number;
|
|
9
|
-
hours?: number;
|
|
10
|
-
tables?: "SUMMARY_AND_HISTORY" | "CLUSTER_SUMMARY_AND_HISTORY";
|
|
11
|
-
}
|
|
12
|
-
interface TriggerResponse {
|
|
13
|
-
headers: {
|
|
14
|
-
"Content-Type": string[];
|
|
15
|
-
};
|
|
16
|
-
statusCode: number;
|
|
17
|
-
statusText?: string;
|
|
18
|
-
body: string;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Performance monitoring scheduler trigger for Atlassian Forge SQL.
|
|
22
|
-
*
|
|
23
|
-
* This trigger analyzes query performance from the last hour and identifies slow or memory-intensive queries
|
|
24
|
-
* that exceed configurable thresholds. It's designed specifically for Atlassian Forge's 16 MiB memory limit
|
|
25
|
-
* and provides detailed insights for query optimization.
|
|
26
|
-
*
|
|
27
|
-
* ## Key Features
|
|
28
|
-
* - **Memory-focused monitoring**: Primary focus on memory usage with configurable thresholds
|
|
29
|
-
* - **Atlassian 16 MiB limit awareness**: Designed specifically for Forge SQL's memory constraints
|
|
30
|
-
* - **Execution plan analysis**: Shows detailed query plans to help optimize memory consumption
|
|
31
|
-
* - **Configurable thresholds**: Set custom memory usage and latency thresholds
|
|
32
|
-
* - **Automatic filtering**: Excludes system queries (`Use`, `Set`, `Show`) and empty queries
|
|
33
|
-
* - **Scheduled monitoring**: Run automatically on configurable intervals
|
|
34
|
-
*
|
|
35
|
-
* ## OR Logic Thresholds
|
|
36
|
-
* Statements are included if they exceed **EITHER** threshold:
|
|
37
|
-
* - `avgLatencyMs > warnThresholdMs` **OR**
|
|
38
|
-
* - `avgMemBytes > memoryThresholdBytes`
|
|
39
|
-
*
|
|
40
|
-
* ## Configuration Tips
|
|
41
|
-
* - **Memory-only monitoring**: Set `warnThresholdMs` to 10000ms (effectively disabled)
|
|
42
|
-
* - **Latency-only monitoring**: Set `memoryThresholdBytes` to 16MB (16 * 1024 * 1024) (effectively disabled)
|
|
43
|
-
* - **Combined monitoring**: Use both thresholds for comprehensive monitoring
|
|
44
|
-
* - **Conservative monitoring**: 4MB warning (25% of 16MB limit)
|
|
45
|
-
* - **Default monitoring**: 8MB warning (50% of 16MB limit)
|
|
46
|
-
* - **Aggressive monitoring**: 12MB warning (75% of 16MB limit)
|
|
47
|
-
*
|
|
48
|
-
* ## Exclusions
|
|
49
|
-
* - Statements with empty `digestText` or `digest`
|
|
50
|
-
* - Service statements (`Use`, `Set`, `Show`)
|
|
51
|
-
* - Queries that don't exceed either threshold
|
|
52
|
-
*
|
|
53
|
-
* @param orm - ForgeSQL ORM instance (required)
|
|
54
|
-
* @param options - Configuration options
|
|
55
|
-
* @param options.warnThresholdMs - Milliseconds threshold for latency monitoring (default: 300ms)
|
|
56
|
-
* @param options.memoryThresholdBytes - Bytes threshold for memory usage monitoring (default: 8MB)
|
|
57
|
-
* @param options.showPlan - Whether to include execution plan in logs (default: false)
|
|
58
|
-
* @param options.operationType - Operation type context for query execution (default: "DML")
|
|
59
|
-
* @param options.topN - Number of top slow queries to return (default: 1)
|
|
60
|
-
* @param options.hours - Number of hours to look back (default: 1)
|
|
61
|
-
* @param options.tables - Table configuration to use (default: "CLUSTER_SUMMARY_AND_HISTORY")
|
|
62
|
-
* @returns Promise<TriggerResponse> - HTTP response with query results or error
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```typescript
|
|
66
|
-
* import ForgeSQL, { topSlowestStatementLastHourTrigger } from "forge-sql-orm";
|
|
67
|
-
*
|
|
68
|
-
* const forgeSQL = new ForgeSQL();
|
|
69
|
-
*
|
|
70
|
-
* // Default thresholds: 300ms latency OR 8MB memory
|
|
71
|
-
* export const performanceTrigger = () =>
|
|
72
|
-
* topSlowestStatementLastHourTrigger(forgeSQL);
|
|
73
|
-
*
|
|
74
|
-
* // Conservative memory monitoring: 4MB threshold
|
|
75
|
-
* export const conservativeTrigger = () =>
|
|
76
|
-
* topSlowestStatementLastHourTrigger(forgeSQL, {
|
|
77
|
-
* memoryThresholdBytes: 4 * 1024 * 1024
|
|
78
|
-
* });
|
|
79
|
-
*
|
|
80
|
-
* // Memory-only monitoring: 4MB threshold (latency effectively disabled)
|
|
81
|
-
* export const memoryOnlyTrigger = () =>
|
|
82
|
-
* topSlowestStatementLastHourTrigger(forgeSQL, {
|
|
83
|
-
* warnThresholdMs: 10000,
|
|
84
|
-
* memoryThresholdBytes: 4 * 1024 * 1024
|
|
85
|
-
* });
|
|
86
|
-
*
|
|
87
|
-
* // With execution plan in logs
|
|
88
|
-
* export const withPlanTrigger = () =>
|
|
89
|
-
* topSlowestStatementLastHourTrigger(forgeSQL, { showPlan: true });
|
|
90
|
-
* ```
|
|
91
|
-
*
|
|
92
|
-
* @example
|
|
93
|
-
* ```yaml
|
|
94
|
-
* # manifest.yml configuration
|
|
95
|
-
* scheduledTrigger:
|
|
96
|
-
* - key: performance-trigger
|
|
97
|
-
* function: performanceTrigger
|
|
98
|
-
* interval: hour
|
|
99
|
-
*
|
|
100
|
-
* function:
|
|
101
|
-
* - key: performanceTrigger
|
|
102
|
-
* handler: index.performanceTrigger
|
|
103
|
-
* ```
|
|
104
|
-
*/
|
|
105
|
-
/**
|
|
106
|
-
* Main scheduler trigger function to log the single slowest SQL statement from the last hour.
|
|
107
|
-
*
|
|
108
|
-
* @param orm - ForgeSQL ORM instance (required)
|
|
109
|
-
* @param options - Configuration options
|
|
110
|
-
* @returns Promise<TriggerResponse> - HTTP response with query results or error
|
|
111
|
-
*/
|
|
112
|
-
export declare const topSlowestStatementLastHourTrigger: (orm: ForgeSqlOperation, options?: TriggerOptions) => Promise<TriggerResponse>;
|
|
113
|
-
export {};
|
|
114
|
-
//# sourceMappingURL=topSlowestStatementLastHourTrigger.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"topSlowestStatementLastHourTrigger.d.ts","sourceRoot":"","sources":["../../src/webtriggers/topSlowestStatementLastHourTrigger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AASjE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAcjE,UAAU,cAAc;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,qBAAqB,GAAG,6BAA6B,CAAC;CAChE;AA2BD,UAAU,eAAe;IACvB,OAAO,EAAE;QAAE,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAgWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AACH;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,GAC7C,KAAK,iBAAiB,EACtB,UAAU,cAAc,KACvB,OAAO,CAAC,eAAe,CAoDzB,CAAC"}
|