nsgm-cli 2.1.22 → 2.1.23
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/client/utils/common.ts +6 -2
- package/client/utils/fetch.ts +1 -1
- package/client/utils/sso.ts +13 -3
- package/lib/generate_create.js +9 -0
- package/lib/generators/dataloader-generator.d.ts +12 -0
- package/lib/generators/dataloader-generator.js +221 -0
- package/lib/generators/resolver-generator.d.ts +2 -1
- package/lib/generators/resolver-generator.js +117 -24
- package/lib/generators/schema-generator.js +1 -0
- package/lib/server/dataloaders/index.d.ts +38 -0
- package/lib/server/dataloaders/index.js +33 -0
- package/lib/server/dataloaders/template-dataloader.d.ts +48 -0
- package/lib/server/dataloaders/template-dataloader.js +131 -0
- package/lib/server/debug/dataloader-debug.d.ts +63 -0
- package/lib/server/debug/dataloader-debug.js +192 -0
- package/lib/server/graphql.js +9 -0
- package/lib/server/utils/dataloader-monitor.d.ts +87 -0
- package/lib/server/utils/dataloader-monitor.js +199 -0
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/utils.js +1 -1
- package/next-i18next.config.js +7 -5
- package/next.config.js +19 -3
- package/package.json +2 -1
- package/pages/_app.tsx +6 -3
- package/pages/api/sso/ticketCheck.ts +117 -0
- package/pages/index.tsx +10 -2
- package/pages/login.tsx +40 -10
- package/pages/template/manage.tsx +15 -1
- package/server/apis/sso.js +22 -4
- package/server/modules/template/resolver.js +101 -21
- package/server/modules/template/schema.js +1 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataLoaderMonitor = void 0;
|
|
4
|
+
exports.createDataLoaderPerformanceMiddleware = createDataLoaderPerformanceMiddleware;
|
|
5
|
+
exports.getDataLoaderHealth = getDataLoaderHealth;
|
|
6
|
+
const dataloaders_1 = require("../dataloaders");
|
|
7
|
+
/**
|
|
8
|
+
* DataLoader 性能监控和调试工具
|
|
9
|
+
*/
|
|
10
|
+
class DataLoaderMonitor {
|
|
11
|
+
/**
|
|
12
|
+
* 记录 DataLoader 请求统计
|
|
13
|
+
*/
|
|
14
|
+
static recordRequest(loaderName, isBatch, batchSize) {
|
|
15
|
+
const stats = this.requestStats.get(loaderName) || {
|
|
16
|
+
totalRequests: 0,
|
|
17
|
+
batchRequests: 0,
|
|
18
|
+
cacheHits: 0,
|
|
19
|
+
cacheMisses: 0,
|
|
20
|
+
averageBatchSize: 0,
|
|
21
|
+
lastActivity: new Date(),
|
|
22
|
+
};
|
|
23
|
+
stats.totalRequests++;
|
|
24
|
+
if (isBatch) {
|
|
25
|
+
stats.batchRequests++;
|
|
26
|
+
if (batchSize) {
|
|
27
|
+
stats.averageBatchSize = (stats.averageBatchSize + batchSize) / 2;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
stats.lastActivity = new Date();
|
|
31
|
+
this.requestStats.set(loaderName, stats);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 记录缓存命中/未命中
|
|
35
|
+
*/
|
|
36
|
+
static recordCacheResult(loaderName, isHit) {
|
|
37
|
+
const stats = this.requestStats.get(loaderName);
|
|
38
|
+
if (stats) {
|
|
39
|
+
if (isHit) {
|
|
40
|
+
stats.cacheHits++;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
stats.cacheMisses++;
|
|
44
|
+
}
|
|
45
|
+
this.requestStats.set(loaderName, stats);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 获取所有 DataLoader 统计信息
|
|
50
|
+
*/
|
|
51
|
+
static getAllStats() {
|
|
52
|
+
const stats = Object.fromEntries(this.requestStats);
|
|
53
|
+
return {
|
|
54
|
+
summary: {
|
|
55
|
+
totalLoaders: this.requestStats.size,
|
|
56
|
+
totalRequests: Array.from(this.requestStats.values()).reduce((sum, stat) => sum + stat.totalRequests, 0),
|
|
57
|
+
totalBatchRequests: Array.from(this.requestStats.values()).reduce((sum, stat) => sum + stat.batchRequests, 0),
|
|
58
|
+
totalCacheHits: Array.from(this.requestStats.values()).reduce((sum, stat) => sum + stat.cacheHits, 0),
|
|
59
|
+
totalCacheMisses: Array.from(this.requestStats.values()).reduce((sum, stat) => sum + stat.cacheMisses, 0),
|
|
60
|
+
},
|
|
61
|
+
loaders: stats,
|
|
62
|
+
generatedAt: new Date().toISOString(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 获取 DataLoader 缓存效率报告
|
|
67
|
+
*/
|
|
68
|
+
static getCacheEfficiencyReport() {
|
|
69
|
+
const report = [];
|
|
70
|
+
this.requestStats.forEach((stats, loaderName) => {
|
|
71
|
+
const totalCacheRequests = stats.cacheHits + stats.cacheMisses;
|
|
72
|
+
const hitRate = totalCacheRequests > 0 ? (stats.cacheHits / totalCacheRequests) * 100 : 0;
|
|
73
|
+
const batchEfficiency = stats.totalRequests > 0 ? (stats.batchRequests / stats.totalRequests) * 100 : 0;
|
|
74
|
+
report.push({
|
|
75
|
+
loader: loaderName,
|
|
76
|
+
hitRate: `${hitRate.toFixed(2)}%`,
|
|
77
|
+
batchEfficiency: `${batchEfficiency.toFixed(2)}%`,
|
|
78
|
+
averageBatchSize: stats.averageBatchSize.toFixed(2),
|
|
79
|
+
totalRequests: stats.totalRequests,
|
|
80
|
+
lastActivity: stats.lastActivity.toISOString(),
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
return report.sort((a, b) => b.totalRequests - a.totalRequests);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 重置统计信息
|
|
87
|
+
*/
|
|
88
|
+
static resetStats() {
|
|
89
|
+
this.requestStats.clear();
|
|
90
|
+
console.log("📊 DataLoader 统计信息已重置");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 打印性能报告到控制台
|
|
94
|
+
*/
|
|
95
|
+
static printPerformanceReport() {
|
|
96
|
+
const stats = this.getAllStats();
|
|
97
|
+
const efficiency = this.getCacheEfficiencyReport();
|
|
98
|
+
console.log("\n📊 DataLoader 性能报告");
|
|
99
|
+
console.log("========================");
|
|
100
|
+
console.log(`总加载器数量: ${stats.summary.totalLoaders}`);
|
|
101
|
+
console.log(`总请求数: ${stats.summary.totalRequests}`);
|
|
102
|
+
console.log(`批量请求数: ${stats.summary.totalBatchRequests}`);
|
|
103
|
+
console.log(`缓存命中数: ${stats.summary.totalCacheHits}`);
|
|
104
|
+
console.log(`缓存未命中数: ${stats.summary.totalCacheMisses}`);
|
|
105
|
+
if (stats.summary.totalCacheHits + stats.summary.totalCacheMisses > 0) {
|
|
106
|
+
const overallHitRate = ((stats.summary.totalCacheHits / (stats.summary.totalCacheHits + stats.summary.totalCacheMisses)) *
|
|
107
|
+
100).toFixed(2);
|
|
108
|
+
console.log(`总体缓存命中率: ${overallHitRate}%`);
|
|
109
|
+
}
|
|
110
|
+
console.log("\n各加载器效率:");
|
|
111
|
+
efficiency.forEach((loader) => {
|
|
112
|
+
console.log(` ${loader.loader}:`);
|
|
113
|
+
console.log(` 缓存命中率: ${loader.hitRate}`);
|
|
114
|
+
console.log(` 批量效率: ${loader.batchEfficiency}`);
|
|
115
|
+
console.log(` 平均批量大小: ${loader.averageBatchSize}`);
|
|
116
|
+
console.log(` 总请求数: ${loader.totalRequests}`);
|
|
117
|
+
});
|
|
118
|
+
console.log("========================\n");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.DataLoaderMonitor = DataLoaderMonitor;
|
|
122
|
+
DataLoaderMonitor.requestStats = new Map();
|
|
123
|
+
/**
|
|
124
|
+
* 创建 DataLoader 性能中间件
|
|
125
|
+
*/
|
|
126
|
+
function createDataLoaderPerformanceMiddleware() {
|
|
127
|
+
return (req, res, next) => {
|
|
128
|
+
const startTime = Date.now();
|
|
129
|
+
// 在响应结束时记录性能数据
|
|
130
|
+
res.on("finish", () => {
|
|
131
|
+
const duration = Date.now() - startTime;
|
|
132
|
+
if (req.body?.query) {
|
|
133
|
+
const isQuery = req.body.query.trim().toLowerCase().startsWith("query");
|
|
134
|
+
const isMutation = req.body.query.trim().toLowerCase().startsWith("mutation");
|
|
135
|
+
if (isQuery || isMutation) {
|
|
136
|
+
console.log(`🚀 GraphQL ${isQuery ? "Query" : "Mutation"} 执行时间: ${duration}ms`);
|
|
137
|
+
// 每10个请求打印一次性能报告
|
|
138
|
+
if (Math.random() < 0.1) {
|
|
139
|
+
DataLoaderMonitor.printPerformanceReport();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
next();
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 获取 DataLoader 健康状态
|
|
149
|
+
*/
|
|
150
|
+
function getDataLoaderHealth(context) {
|
|
151
|
+
const stats = DataLoaderMonitor.getAllStats();
|
|
152
|
+
const efficiency = DataLoaderMonitor.getCacheEfficiencyReport();
|
|
153
|
+
// 计算健康分数
|
|
154
|
+
let healthScore = 100;
|
|
155
|
+
efficiency.forEach((loader) => {
|
|
156
|
+
const hitRate = parseFloat(loader.hitRate);
|
|
157
|
+
const batchEfficiency = parseFloat(loader.batchEfficiency);
|
|
158
|
+
// 缓存命中率低于50%扣分
|
|
159
|
+
if (hitRate < 50) {
|
|
160
|
+
healthScore -= 10;
|
|
161
|
+
}
|
|
162
|
+
// 批量效率低于30%扣分
|
|
163
|
+
if (batchEfficiency < 30) {
|
|
164
|
+
healthScore -= 15;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
const status = healthScore >= 80 ? "healthy" : healthScore >= 60 ? "warning" : "critical";
|
|
168
|
+
return {
|
|
169
|
+
status,
|
|
170
|
+
score: Math.max(0, healthScore),
|
|
171
|
+
summary: stats.summary,
|
|
172
|
+
loaders: efficiency,
|
|
173
|
+
recommendations: generateRecommendations(efficiency),
|
|
174
|
+
contextStats: context ? (0, dataloaders_1.getDataLoaderStats)(context) : null,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 生成性能优化建议
|
|
179
|
+
*/
|
|
180
|
+
function generateRecommendations(efficiency) {
|
|
181
|
+
const recommendations = [];
|
|
182
|
+
efficiency.forEach((loader) => {
|
|
183
|
+
const hitRate = parseFloat(loader.hitRate);
|
|
184
|
+
const batchEfficiency = parseFloat(loader.batchEfficiency);
|
|
185
|
+
if (hitRate < 50) {
|
|
186
|
+
recommendations.push(`${loader.loader}: 考虑增加缓存时间或优化查询模式以提高缓存命中率`);
|
|
187
|
+
}
|
|
188
|
+
if (batchEfficiency < 30) {
|
|
189
|
+
recommendations.push(`${loader.loader}: 考虑调整 batchScheduleFn 延迟时间以提高批量效率`);
|
|
190
|
+
}
|
|
191
|
+
if (parseFloat(loader.averageBatchSize) < 2) {
|
|
192
|
+
recommendations.push(`${loader.loader}: 批量大小较小,可能需要优化查询时机`);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
if (recommendations.length === 0) {
|
|
196
|
+
recommendations.push("DataLoader 性能表现良好,无需优化");
|
|
197
|
+
}
|
|
198
|
+
return recommendations;
|
|
199
|
+
}
|