@flink-app/flink 2.0.0-alpha.51 → 2.0.0-alpha.53

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/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # @flink-app/flink
2
2
 
3
+ ## 2.0.0-alpha.53
4
+
5
+ ### Minor Changes
6
+
7
+ - 333aa52: feat: add worker thread parallelization for JSON schema generation
8
+
9
+ Implements worker thread pool for parallel JSON schema generation during compilation, providing significant speedup for large projects with 50+ schemas.
10
+
11
+ **Key features:**
12
+
13
+ - Worker pool with automatic sizing based on CPU cores and memory
14
+ - Parallel schema generation using ts-json-schema-generator
15
+ - Automatic fallback to single-threaded mode for small projects (<50 schemas)
16
+ - Configurable via environment variables:
17
+ - `FLINK_USE_WORKERS=false` to disable workers entirely
18
+ - `FLINK_WORKER_THRESHOLD=N` to customize the schema count threshold
19
+ - Graceful error handling with automatic cleanup
20
+ - Identical output to single-threaded mode (verified)
21
+
22
+ **Performance:**
23
+
24
+ - Projects with 50+ schemas: ~2-2.5x speedup expected
25
+ - Projects with <50 schemas: Uses efficient single-threaded mode (no overhead)
26
+ - Memory overhead: ~80-160MB for worker pool (scales with CPU count)
27
+
28
+ **Usage:**
29
+ No configuration needed - workers are automatically enabled for large projects. To disable:
30
+
31
+ ```bash
32
+ FLINK_USE_WORKERS=false flink build
33
+ ```
34
+
35
+ To customize threshold:
36
+
37
+ ```bash
38
+ FLINK_WORKER_THRESHOLD=30 flink build
39
+ ```
40
+
41
+ ## 2.0.0-alpha.52
42
+
43
+ ### Patch Changes
44
+
45
+ - fe9f8f2: Improved compilation performance by parallelizing handler schema extraction. Projects with many handlers (90+) will see 3-10x faster build times.
46
+
3
47
  ## 2.0.0-alpha.51
4
48
 
5
49
  ## 2.0.0-alpha.50
package/cli/build.ts CHANGED
@@ -40,16 +40,21 @@ module.exports = async function run(args: string[]) {
40
40
  process.exit(1);
41
41
  }
42
42
 
43
- await Promise.all([
44
- compiler.parseRepos(),
45
- compiler.parseHandlers(exclude.split(",")),
46
- compiler.parseTools(),
47
- compiler.parseAgents(),
48
- compiler.parseJobs(),
49
- compiler.generateStartScript(),
50
- ]);
51
-
52
- console.log(`Compilation done, took ${Date.now() - startTime}ms`);
53
-
54
- compiler.emit();
43
+ try {
44
+ await Promise.all([
45
+ compiler.parseRepos(),
46
+ compiler.parseHandlers(exclude.split(",")),
47
+ compiler.parseTools(),
48
+ compiler.parseAgents(),
49
+ compiler.parseJobs(),
50
+ compiler.generateStartScript(),
51
+ ]);
52
+
53
+ console.log(`Compilation done, took ${Date.now() - startTime}ms`);
54
+
55
+ compiler.emit();
56
+ } finally {
57
+ // Cleanup worker pool and other resources
58
+ await compiler.cleanup();
59
+ }
55
60
  };
package/dist/cli/build.js CHANGED
@@ -65,6 +65,9 @@ module.exports = function run(args) {
65
65
  if (!compiler.getPreEmitDiagnostics()) {
66
66
  process.exit(1);
67
67
  }
68
+ _a.label = 2;
69
+ case 2:
70
+ _a.trys.push([2, , 4, 6]);
68
71
  return [4 /*yield*/, Promise.all([
69
72
  compiler.parseRepos(),
70
73
  compiler.parseHandlers(exclude.split(",")),
@@ -73,11 +76,19 @@ module.exports = function run(args) {
73
76
  compiler.parseJobs(),
74
77
  compiler.generateStartScript(),
75
78
  ])];
76
- case 2:
79
+ case 3:
77
80
  _a.sent();
78
81
  console.log("Compilation done, took ".concat(Date.now() - startTime, "ms"));
79
82
  compiler.emit();
80
- return [2 /*return*/];
83
+ return [3 /*break*/, 6];
84
+ case 4:
85
+ // Cleanup worker pool and other resources
86
+ return [4 /*yield*/, compiler.cleanup()];
87
+ case 5:
88
+ // Cleanup worker pool and other resources
89
+ _a.sent();
90
+ return [7 /*endfinally*/];
91
+ case 6: return [2 /*return*/];
81
92
  }
82
93
  });
83
94
  });
@@ -4,6 +4,11 @@ declare class TypeScriptCompiler {
4
4
  private project;
5
5
  private schemaGenerator?;
6
6
  private isEsm;
7
+ /**
8
+ * Worker pool for parallel JSON schema generation.
9
+ * Initialized on first use, terminated on cleanup.
10
+ */
11
+ private workerPool?;
7
12
  /**
8
13
  * Parsed typescript schemas that will be added to intermediate
9
14
  * schemas.ts file.
@@ -17,6 +22,11 @@ declare class TypeScriptCompiler {
17
22
  * This will be added to file in a batch for performance reasons.
18
23
  */
19
24
  private tsSchemasSymbolsToImports;
25
+ /**
26
+ * Cache for schema analysis to avoid reprocessing the same types.
27
+ * Key: schema type text, Value: generated schema interface name
28
+ */
29
+ private schemaCache;
20
30
  constructor(cwd: string);
21
31
  /**
22
32
  * Loads additional source paths from tsconfig.json's flink configuration.
@@ -138,6 +148,10 @@ declare class TypeScriptCompiler {
138
148
  private saveIntermediateTsSchema;
139
149
  private initJsonSchemaGenerator;
140
150
  private generateAndSaveJsonSchemas;
151
+ /**
152
+ * Generate schemas sequentially (single-threaded fallback)
153
+ */
154
+ private generateSchemasSequentially;
141
155
  private generateJsonSchema;
142
156
  private extractSchemaTypeFromHandler;
143
157
  /**
@@ -164,5 +178,9 @@ declare class TypeScriptCompiler {
164
178
  * Scans project for jobs so they can be registered during start.
165
179
  */
166
180
  parseJobs(): Promise<SourceFile>;
181
+ /**
182
+ * Cleanup resources, including worker pool
183
+ */
184
+ cleanup(): Promise<void>;
167
185
  }
168
186
  export default TypeScriptCompiler;
@@ -90,6 +90,7 @@ var ts_morph_1 = require("ts-morph");
90
90
  var FsUtils_1 = require("./FsUtils");
91
91
  var TypeScriptUtils_1 = require("./TypeScriptUtils");
92
92
  var utils_1 = require("./utils");
93
+ var WorkerPool_1 = require("./workers/WorkerPool");
93
94
  var TypeScriptCompiler = /** @class */ (function () {
94
95
  function TypeScriptCompiler(cwd) {
95
96
  this.cwd = cwd;
@@ -106,6 +107,11 @@ var TypeScriptCompiler = /** @class */ (function () {
106
107
  * This will be added to file in a batch for performance reasons.
107
108
  */
108
109
  this.tsSchemasSymbolsToImports = [];
110
+ /**
111
+ * Cache for schema analysis to avoid reprocessing the same types.
112
+ * Key: schema type text, Value: generated schema interface name
113
+ */
114
+ this.schemaCache = new Map();
109
115
  // Detect if project is using ESM based solely on package.json "type": "module"
110
116
  this.isEsm = this.isEsmProject(cwd);
111
117
  var compilerOptions = {
@@ -385,20 +391,24 @@ var TypeScriptCompiler = /** @class */ (function () {
385
391
  */
386
392
  TypeScriptCompiler.prototype.parseHandlers = function () {
387
393
  return __awaiter(this, arguments, void 0, function (excludeDirs) {
388
- var generatedFile, handlersArr, handlers, schemaFilePath, jsonSchemas;
394
+ var startTime, generatedFile, handlersArr, handlers, handlerParseTime, schemaGenStartTime, schemaFilePath, jsonSchemas, schemaGenTime;
389
395
  if (excludeDirs === void 0) { excludeDirs = []; }
390
396
  return __generator(this, function (_a) {
391
397
  switch (_a.label) {
392
398
  case 0:
399
+ startTime = Date.now();
393
400
  generatedFile = this.createSourceFile(["generatedHandlers.ts"], "// Generated ".concat(new Date(), "\nimport { autoRegisteredHandlers, HttpMethod } from \"@flink-app/flink\";\nexport const handlers = [];\nautoRegisteredHandlers.push(...handlers);\n "));
394
401
  handlersArr = generatedFile.getVariableDeclarationOrThrow("handlers").getFirstDescendantByKindOrThrow(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
395
402
  return [4 /*yield*/, this.parseHandlerDir(generatedFile, handlersArr)];
396
403
  case 1:
397
404
  handlers = _a.sent();
405
+ handlerParseTime = Date.now() - startTime;
406
+ console.log("\u2713 Handler parsing completed in ".concat(handlerParseTime, "ms"));
398
407
  generatedFile.addImportDeclarations(handlers.imports);
399
408
  return [4 /*yield*/, generatedFile.save()];
400
409
  case 2:
401
410
  _a.sent();
411
+ schemaGenStartTime = Date.now();
402
412
  return [4 /*yield*/, this.createIntermediateSchemaFile()];
403
413
  case 3:
404
414
  schemaFilePath = _a.sent();
@@ -406,6 +416,8 @@ var TypeScriptCompiler = /** @class */ (function () {
406
416
  case 4:
407
417
  jsonSchemas = _a.sent();
408
418
  this.appendSchemasToHandlerSourceFiles(handlers.schemasToGenerate, jsonSchemas);
419
+ schemaGenTime = Date.now() - schemaGenStartTime;
420
+ console.log("\u2713 Schema generation completed in ".concat(schemaGenTime, "ms"));
409
421
  return [2 /*return*/, generatedFile];
410
422
  }
411
423
  });
@@ -416,93 +428,111 @@ var TypeScriptCompiler = /** @class */ (function () {
416
428
  */
417
429
  TypeScriptCompiler.prototype.parseHandlerDir = function (generatedFile, handlersArr) {
418
430
  return __awaiter(this, void 0, void 0, function () {
419
- var imports, i, schemasToGenerate, _i, _a, sf, isAutoRegister, namespaceImport, assumedHttpMethod, schemaTypes, _b, existingVars;
420
- return __generator(this, function (_c) {
421
- switch (_c.label) {
431
+ var imports, schemasToGenerate, handlerFiles, handlerResults, autoRegisterIndex, _i, handlerResults_1, result, sf, isAutoRegister, namespaceImport, assumedHttpMethod, schemaTypes, existingVars;
432
+ var _this = this;
433
+ return __generator(this, function (_a) {
434
+ switch (_a.label) {
422
435
  case 0:
423
436
  imports = [];
424
- i = 0;
425
437
  schemasToGenerate = [];
426
- _i = 0, _a = this.project.getSourceFiles();
427
- _c.label = 1;
438
+ handlerFiles = this.project.getSourceFiles().filter(function (sf) { return sf.getFilePath().includes("src/handlers/"); });
439
+ console.log("Processing ".concat(handlerFiles.length, " handlers..."));
440
+ return [4 /*yield*/, Promise.all(handlerFiles.map(function (sf, index) { return __awaiter(_this, void 0, void 0, function () {
441
+ var startTime, isAutoRegister, namespaceImport, assumedHttpMethod, schemaTypes, _a, elapsed;
442
+ return __generator(this, function (_b) {
443
+ switch (_b.label) {
444
+ case 0:
445
+ startTime = Date.now();
446
+ isAutoRegister = this.isAutoRegisterableHandler(sf);
447
+ namespaceImport = sf.getBaseNameWithoutExtension().replace(/\./g, "_") + "_" + index;
448
+ assumedHttpMethod = (0, utils_1.getHttpMethodFromHandlerName)(sf.getBaseName());
449
+ console.log("[".concat(index + 1, "/").concat(handlerFiles.length, "] Processing ").concat(sf.getBaseName(), "..."));
450
+ if (!isAutoRegister) return [3 /*break*/, 2];
451
+ return [4 /*yield*/, this.extractSchemasFromHandlerSourceFile(sf)];
452
+ case 1:
453
+ _a = _b.sent();
454
+ return [3 /*break*/, 3];
455
+ case 2:
456
+ _a = undefined;
457
+ _b.label = 3;
458
+ case 3:
459
+ schemaTypes = _a;
460
+ elapsed = Date.now() - startTime;
461
+ if (elapsed > 100) {
462
+ console.log(" \u2514\u2500 Completed in ".concat(elapsed, "ms"));
463
+ }
464
+ return [2 /*return*/, {
465
+ sf: sf,
466
+ isAutoRegister: isAutoRegister,
467
+ namespaceImport: namespaceImport,
468
+ assumedHttpMethod: assumedHttpMethod,
469
+ schemaTypes: schemaTypes,
470
+ index: index,
471
+ }];
472
+ }
473
+ });
474
+ }); }))];
428
475
  case 1:
429
- if (!(_i < _a.length)) return [3 /*break*/, 6];
430
- sf = _a[_i];
431
- if (!sf.getFilePath().includes("src/handlers/")) {
432
- return [3 /*break*/, 5];
433
- }
434
- isAutoRegister = this.isAutoRegisterableHandler(sf);
435
- console.log("Detected handler ".concat(sf.getBaseName(), " ").concat(!isAutoRegister ? "(requires manual registration)" : ""));
436
- namespaceImport = sf.getBaseNameWithoutExtension().replace(/\./g, "_") + "_" + i;
437
- imports.push({
438
- defaultImport: "* as " + namespaceImport,
439
- moduleSpecifier: this.getModuleSpecifier(generatedFile, sf),
440
- });
441
- assumedHttpMethod = (0, utils_1.getHttpMethodFromHandlerName)(sf.getBaseName());
442
- if (!isAutoRegister) return [3 /*break*/, 3];
443
- return [4 /*yield*/, this.extractSchemasFromHandlerSourceFile(sf)];
444
- case 2:
445
- _b = _c.sent();
446
- return [3 /*break*/, 4];
447
- case 3:
448
- _b = undefined;
449
- _c.label = 4;
450
- case 4:
451
- schemaTypes = _b;
452
- existingVars = sf.getVariableStatements().filter(function (vs) {
453
- var varNames = vs.getDeclarations().map(function (d) { return d.getName(); });
454
- return varNames.some(function (name) { return ["__assumedHttpMethod", "__file", "__query", "__params"].includes(name); });
455
- });
456
- existingVars.forEach(function (v) { return v.remove(); });
457
- // Append schemas and metadata to source file that will be part of emitted dist bundle (javascript)
458
- sf.addVariableStatement({
459
- declarationKind: ts_morph_1.VariableDeclarationKind.Const,
460
- isExported: true,
461
- declarations: [
462
- {
463
- name: "__assumedHttpMethod",
464
- initializer: "\"".concat(assumedHttpMethod || "", "\""),
465
- },
466
- {
467
- name: "__file",
468
- initializer: "\"".concat(sf.getBaseName(), "\""),
469
- },
470
- {
471
- name: "__query",
472
- initializer: "[".concat(((schemaTypes === null || schemaTypes === void 0 ? void 0 : schemaTypes.queryMetadata) || [])
473
- .map(function (_a) {
474
- var description = _a.description, name = _a.name;
475
- return "{description: \"".concat(description, "\", name: \"").concat(name, "\"}");
476
- })
477
- .join(","), "]"),
478
- },
479
- {
480
- name: "__params",
481
- initializer: "[".concat(((schemaTypes === null || schemaTypes === void 0 ? void 0 : schemaTypes.paramsMetadata) || [])
482
- .map(function (_a) {
483
- var description = _a.description, name = _a.name;
484
- return "{description: \"".concat(description, "\", name: \"").concat(name, "\"}");
485
- })
486
- .join(","), "]"),
487
- },
488
- ],
489
- });
490
- if (isAutoRegister) {
491
- handlersArr.insertElement(i, "{handler: ".concat(namespaceImport, ", assumedHttpMethod: ").concat(assumedHttpMethod ? "HttpMethod." + assumedHttpMethod : undefined, "}"));
492
- i++;
493
- // Add schemas to generate list
494
- if (schemaTypes) {
495
- schemasToGenerate.push(__assign(__assign({}, schemaTypes), { sourceFile: sf }));
476
+ handlerResults = _a.sent();
477
+ autoRegisterIndex = 0;
478
+ for (_i = 0, handlerResults_1 = handlerResults; _i < handlerResults_1.length; _i++) {
479
+ result = handlerResults_1[_i];
480
+ sf = result.sf, isAutoRegister = result.isAutoRegister, namespaceImport = result.namespaceImport, assumedHttpMethod = result.assumedHttpMethod, schemaTypes = result.schemaTypes;
481
+ imports.push({
482
+ defaultImport: "* as " + namespaceImport,
483
+ moduleSpecifier: this.getModuleSpecifier(generatedFile, sf),
484
+ });
485
+ existingVars = sf.getVariableStatements().filter(function (vs) {
486
+ var varNames = vs.getDeclarations().map(function (d) { return d.getName(); });
487
+ return varNames.some(function (name) { return ["__assumedHttpMethod", "__file", "__query", "__params"].includes(name); });
488
+ });
489
+ existingVars.forEach(function (v) { return v.remove(); });
490
+ // Append schemas and metadata to source file that will be part of emitted dist bundle (javascript)
491
+ sf.addVariableStatement({
492
+ declarationKind: ts_morph_1.VariableDeclarationKind.Const,
493
+ isExported: true,
494
+ declarations: [
495
+ {
496
+ name: "__assumedHttpMethod",
497
+ initializer: "\"".concat(assumedHttpMethod || "", "\""),
498
+ },
499
+ {
500
+ name: "__file",
501
+ initializer: "\"".concat(sf.getBaseName(), "\""),
502
+ },
503
+ {
504
+ name: "__query",
505
+ initializer: "[".concat(((schemaTypes === null || schemaTypes === void 0 ? void 0 : schemaTypes.queryMetadata) || [])
506
+ .map(function (_a) {
507
+ var description = _a.description, name = _a.name;
508
+ return "{description: \"".concat(description, "\", name: \"").concat(name, "\"}");
509
+ })
510
+ .join(","), "]"),
511
+ },
512
+ {
513
+ name: "__params",
514
+ initializer: "[".concat(((schemaTypes === null || schemaTypes === void 0 ? void 0 : schemaTypes.paramsMetadata) || [])
515
+ .map(function (_a) {
516
+ var description = _a.description, name = _a.name;
517
+ return "{description: \"".concat(description, "\", name: \"").concat(name, "\"}");
518
+ })
519
+ .join(","), "]"),
520
+ },
521
+ ],
522
+ });
523
+ if (isAutoRegister) {
524
+ handlersArr.insertElement(autoRegisterIndex, "{handler: ".concat(namespaceImport, ", assumedHttpMethod: ").concat(assumedHttpMethod ? "HttpMethod." + assumedHttpMethod : undefined, "}"));
525
+ autoRegisterIndex++;
526
+ // Add schemas to generate list
527
+ if (schemaTypes) {
528
+ schemasToGenerate.push(__assign(__assign({}, schemaTypes), { sourceFile: sf }));
529
+ }
496
530
  }
497
531
  }
498
- _c.label = 5;
499
- case 5:
500
- _i++;
501
- return [3 /*break*/, 1];
502
- case 6: return [2 /*return*/, {
503
- imports: imports,
504
- schemasToGenerate: schemasToGenerate,
505
- }];
532
+ return [2 /*return*/, {
533
+ imports: imports,
534
+ schemasToGenerate: schemasToGenerate,
535
+ }];
506
536
  }
507
537
  });
508
538
  });
@@ -884,7 +914,7 @@ var TypeScriptCompiler = /** @class */ (function () {
884
914
  };
885
915
  TypeScriptCompiler.prototype.saveIntermediateTsSchema = function (schema, handlerFile, suffix) {
886
916
  return __awaiter(this, void 0, void 0, function () {
887
- var schemaText, handlerFileName, generatedSchemaInterfaceStr, schemaInterfaceName, schemaSymbol, interfaceName, declaration, _i, _a, typeToImport, typeSymbol, declaredTypeSymbol, _b, _c, prop, propDecl, propText, interfaceNameMatches, _d, interfaceNameMatches_1, match, referencedInterfaceName, referencedInterfaceDecl, arrayTypeArg, schemaSymbol, interfaceName, declaration, props, _e, _f, typeToImport, typeSymbol, declaredTypeSymbol, schemaSymbol, declarations, declaration, propertySignatures, _g, _h, prop, propType, typeSymbol, typeDeclaration, elementType, elementSymbol, elementDeclaration, currentPropTypeText, interfaceNameMatches, _j, interfaceNameMatches_2, match, interfaceName, interfaceDecl, typeArgs, _k, typeArgs_1, typeArg, argSymbol, argDeclaration, _l, _m, typeToImport, typeSymbol, declaredTypeSymbol;
917
+ var schemaText, cacheKey, handlerFileName, generatedSchemaInterfaceStr, schemaInterfaceName, schemaSymbol, interfaceName, declaration, _i, _a, typeToImport, typeSymbol, declaredTypeSymbol, _b, _c, prop, propDecl, propText, interfaceNameMatches, _d, interfaceNameMatches_1, match, referencedInterfaceName, referencedInterfaceDecl, arrayTypeArg, schemaSymbol, interfaceName, declaration, props, _e, _f, typeToImport, typeSymbol, declaredTypeSymbol, schemaSymbol, declarations, declaration, propertySignatures, _g, _h, prop, propType, typeSymbol, typeDeclaration, elementType, elementSymbol, elementDeclaration, currentPropTypeText, interfaceNameMatches, _j, interfaceNameMatches_2, match, interfaceName, interfaceDecl, typeArgs, _k, typeArgs_1, typeArg, argSymbol, argDeclaration, _l, _m, typeToImport, typeSymbol, declaredTypeSymbol;
888
918
  return __generator(this, function (_o) {
889
919
  if (schema.isAny()) {
890
920
  return [2 /*return*/]; // 'any' indicates that no schema is used
@@ -893,6 +923,10 @@ var TypeScriptCompiler = /** @class */ (function () {
893
923
  if (schemaText === "void" || schemaText === "undefined") {
894
924
  return [2 /*return*/];
895
925
  }
926
+ cacheKey = "".concat(handlerFile.getFilePath(), ":").concat(schemaText, ":").concat(suffix);
927
+ if (this.schemaCache.has(cacheKey)) {
928
+ return [2 /*return*/, this.schemaCache.get(cacheKey)];
929
+ }
896
930
  handlerFileName = handlerFile.getBaseNameWithoutExtension().replace(/\./g, "_");
897
931
  generatedSchemaInterfaceStr = "";
898
932
  schemaInterfaceName = "".concat(handlerFileName, "_").concat(suffix);
@@ -1067,8 +1101,10 @@ var TypeScriptCompiler = /** @class */ (function () {
1067
1101
  }
1068
1102
  if (generatedSchemaInterfaceStr) {
1069
1103
  this.parsedTsSchemas.push(generatedSchemaInterfaceStr);
1104
+ this.schemaCache.set(cacheKey, schemaInterfaceName);
1070
1105
  return [2 /*return*/, schemaInterfaceName];
1071
1106
  }
1107
+ this.schemaCache.set(cacheKey, undefined);
1072
1108
  return [2 /*return*/];
1073
1109
  });
1074
1110
  });
@@ -1132,43 +1168,117 @@ var TypeScriptCompiler = /** @class */ (function () {
1132
1168
  };
1133
1169
  TypeScriptCompiler.prototype.generateAndSaveJsonSchemas = function (schemas, schemaFilePath) {
1134
1170
  return __awaiter(this, void 0, void 0, function () {
1135
- var jsonSchemas, _i, schemas_1, _a, reqSchemaType, resSchemaType, mergedSchemas, filePath;
1136
- var _b, _c;
1137
- return __generator(this, function (_d) {
1138
- switch (_d.label) {
1171
+ var tsconfigPath, useWorkers, workerThreshold, schemaTypes, _i, schemas_1, _a, reqSchemaType, resSchemaType, definitions, workerScriptPath, stats, startTime, results, duration, _b, results_1, result, error_1, mergedSchemas, filePath;
1172
+ var _this = this;
1173
+ return __generator(this, function (_c) {
1174
+ switch (_c.label) {
1139
1175
  case 0:
1140
1176
  // Reset schema generator to use the newly created intermediate schema file
1141
1177
  this.schemaGenerator = undefined;
1142
- jsonSchemas = [];
1178
+ tsconfigPath = (0, path_1.join)(this.cwd, "tsconfig.json");
1179
+ useWorkers = process.env.FLINK_USE_WORKERS !== "false";
1180
+ workerThreshold = parseInt(process.env.FLINK_WORKER_THRESHOLD || "50", 10);
1181
+ schemaTypes = [];
1143
1182
  for (_i = 0, schemas_1 = schemas; _i < schemas_1.length; _i++) {
1144
1183
  _a = schemas_1[_i], reqSchemaType = _a.reqSchemaType, resSchemaType = _a.resSchemaType;
1145
- if (reqSchemaType) {
1146
- jsonSchemas.push({ definitions: (_b = {}, _b[reqSchemaType] = this.generateJsonSchema(reqSchemaType, schemaFilePath), _b) });
1147
- }
1148
- if (resSchemaType) {
1149
- jsonSchemas.push({ definitions: (_c = {}, _c[resSchemaType] = this.generateJsonSchema(resSchemaType, schemaFilePath), _c) });
1150
- }
1184
+ if (reqSchemaType)
1185
+ schemaTypes.push(reqSchemaType);
1186
+ if (resSchemaType)
1187
+ schemaTypes.push(resSchemaType);
1151
1188
  }
1152
- mergedSchemas = jsonSchemas.reduce(function (out, schema) {
1153
- if (schema.definitions) {
1154
- out.definitions = __assign(__assign({}, out.definitions), schema.definitions);
1189
+ definitions = {};
1190
+ if (!(useWorkers && schemaTypes.length >= workerThreshold)) return [3 /*break*/, 10];
1191
+ _c.label = 1;
1192
+ case 1:
1193
+ _c.trys.push([1, 5, , 9]);
1194
+ if (!!this.workerPool) return [3 /*break*/, 3];
1195
+ workerScriptPath = (0, path_1.join)(__dirname, "workers", "SchemaGeneratorWorker.js");
1196
+ this.workerPool = new WorkerPool_1.WorkerPool(workerScriptPath);
1197
+ return [4 /*yield*/, this.workerPool.initialize()];
1198
+ case 2:
1199
+ _c.sent();
1200
+ stats = this.workerPool.getStats();
1201
+ console.log("\u2713 Worker pool initialized with ".concat(stats.poolSize, " workers"));
1202
+ _c.label = 3;
1203
+ case 3:
1204
+ startTime = Date.now();
1205
+ return [4 /*yield*/, Promise.all(schemaTypes.map(function (typeName) {
1206
+ return _this.workerPool.execute({ schemaFilePath: schemaFilePath, typeName: typeName, tsconfigPath: tsconfigPath });
1207
+ }))];
1208
+ case 4:
1209
+ results = _c.sent();
1210
+ duration = Date.now() - startTime;
1211
+ console.log("\u2713 Generated ".concat(schemaTypes.length, " schemas in ").concat(duration, "ms using workers"));
1212
+ // Merge results
1213
+ for (_b = 0, results_1 = results; _b < results_1.length; _b++) {
1214
+ result = results_1[_b];
1215
+ if (result.error) {
1216
+ throw new Error("Schema generation failed for ".concat(result.typeName, ": ").concat(result.error));
1155
1217
  }
1156
- return out;
1157
- }, {
1218
+ definitions[result.typeName] = result.schema;
1219
+ }
1220
+ return [3 /*break*/, 9];
1221
+ case 5:
1222
+ error_1 = _c.sent();
1223
+ console.warn("Worker pool failed, falling back to single-threaded mode:", error_1.message);
1224
+ if (!this.workerPool) return [3 /*break*/, 7];
1225
+ return [4 /*yield*/, this.workerPool.terminate().catch(function () { })];
1226
+ case 6:
1227
+ _c.sent();
1228
+ this.workerPool = undefined;
1229
+ _c.label = 7;
1230
+ case 7: return [4 /*yield*/, this.generateSchemasSequentially(schemas, schemaFilePath)];
1231
+ case 8:
1232
+ // Fall back to single-threaded generation
1233
+ definitions = _c.sent();
1234
+ return [3 /*break*/, 9];
1235
+ case 9: return [3 /*break*/, 12];
1236
+ case 10:
1237
+ // Use single-threaded generation for small schema counts or when workers disabled
1238
+ if (!useWorkers) {
1239
+ console.log("✓ Workers disabled, using single-threaded schema generation");
1240
+ }
1241
+ return [4 /*yield*/, this.generateSchemasSequentially(schemas, schemaFilePath)];
1242
+ case 11:
1243
+ definitions = _c.sent();
1244
+ _c.label = 12;
1245
+ case 12:
1246
+ mergedSchemas = {
1158
1247
  $schema: "http://json-schema.org/draft-07/schema#",
1159
1248
  $ref: "#/definitions/Schemas",
1160
- definitions: {},
1161
- });
1249
+ definitions: definitions,
1250
+ };
1162
1251
  filePath = (0, path_1.join)(this.cwd, ".flink", "schemas", "schemas.json");
1163
1252
  return [4 /*yield*/, (0, FsUtils_1.writeJsonFile)(filePath, mergedSchemas)];
1164
- case 1:
1165
- _d.sent();
1253
+ case 13:
1254
+ _c.sent();
1166
1255
  this.project.addSourceFileAtPath(filePath);
1167
1256
  return [2 /*return*/, mergedSchemas];
1168
1257
  }
1169
1258
  });
1170
1259
  });
1171
1260
  };
1261
+ /**
1262
+ * Generate schemas sequentially (single-threaded fallback)
1263
+ */
1264
+ TypeScriptCompiler.prototype.generateSchemasSequentially = function (schemas, schemaFilePath) {
1265
+ return __awaiter(this, void 0, void 0, function () {
1266
+ var definitions, _i, schemas_2, _a, reqSchemaType, resSchemaType;
1267
+ return __generator(this, function (_b) {
1268
+ definitions = {};
1269
+ for (_i = 0, schemas_2 = schemas; _i < schemas_2.length; _i++) {
1270
+ _a = schemas_2[_i], reqSchemaType = _a.reqSchemaType, resSchemaType = _a.resSchemaType;
1271
+ if (reqSchemaType) {
1272
+ definitions[reqSchemaType] = this.generateJsonSchema(reqSchemaType, schemaFilePath);
1273
+ }
1274
+ if (resSchemaType) {
1275
+ definitions[resSchemaType] = this.generateJsonSchema(resSchemaType, schemaFilePath);
1276
+ }
1277
+ }
1278
+ return [2 /*return*/, definitions];
1279
+ });
1280
+ });
1281
+ };
1172
1282
  TypeScriptCompiler.prototype.generateJsonSchema = function (typeName, schemaFilePath) {
1173
1283
  if (!this.schemaGenerator) {
1174
1284
  this.schemaGenerator = this.initJsonSchemaGenerator(schemaFilePath);
@@ -1349,6 +1459,25 @@ var TypeScriptCompiler = /** @class */ (function () {
1349
1459
  });
1350
1460
  });
1351
1461
  };
1462
+ /**
1463
+ * Cleanup resources, including worker pool
1464
+ */
1465
+ TypeScriptCompiler.prototype.cleanup = function () {
1466
+ return __awaiter(this, void 0, void 0, function () {
1467
+ return __generator(this, function (_a) {
1468
+ switch (_a.label) {
1469
+ case 0:
1470
+ if (!this.workerPool) return [3 /*break*/, 2];
1471
+ return [4 /*yield*/, this.workerPool.terminate()];
1472
+ case 1:
1473
+ _a.sent();
1474
+ this.workerPool = undefined;
1475
+ _a.label = 2;
1476
+ case 2: return [2 /*return*/];
1477
+ }
1478
+ });
1479
+ });
1480
+ };
1352
1481
  return TypeScriptCompiler;
1353
1482
  }());
1354
1483
  exports.default = TypeScriptCompiler;
@@ -0,0 +1 @@
1
+ export {};