11'use strict' ;
22
3- import { Worker , isMainThread , parentPort , workerData } from 'worker_threads' ;
4- import os from 'os' ;
5-
6- import publicGenerators from './generators/index.mjs' ;
7- import astJs from './generators/ast-js/index.mjs' ;
8- import oramaDb from './generators/orama-db/index.mjs' ;
9-
10- const availableGenerators = {
11- ...publicGenerators ,
12- // This one is a little special since we don't want it to run unless we need
13- // it and we also don't want it to be publicly accessible through the CLI.
14- 'ast-js' : astJs ,
15- 'orama-db' : oramaDb ,
16- } ;
17-
18- // Thread pool max limit
19- const MAX_THREADS = Math . max ( 1 , os . cpus ( ) . length - 1 ) ;
20-
21- // If inside a worker thread, perform the generator logic here
22- if ( ! isMainThread ) {
23- const { name, dependencyOutput, extra } = workerData ;
24- const generator = availableGenerators [ name ] ;
25-
26- // Execute the generator and send the result back to the parent thread
27- generator
28- . generate ( dependencyOutput , extra )
29- . then ( result => {
30- parentPort . postMessage ( result ) ;
31- } )
32- . catch ( error => {
33- parentPort . postMessage ( { error } ) ;
34- } ) ;
35- }
3+ import { allGenerators } from './generators/index.mjs' ;
4+ import { WorkerPool } from './threading.mjs' ;
365
376/**
387 * @typedef {{ ast: GeneratorMetadata<ApiDocMetadataEntry, ApiDocMetadataEntry>} } AstGenerator The AST "generator" is a facade for the AST tree and it isn't really a generator
@@ -65,74 +34,14 @@ const createGenerator = markdownInput => {
6534 */
6635 const cachedGenerators = { ast : Promise . resolve ( markdownInput ) } ;
6736
68- // Keep track of how many threads are currently running
69- let activeThreads = 0 ;
70- const threadQueue = [ ] ;
71-
72- /**
73- * Run the input generator within a worker thread
74- * @param {keyof AllGenerators } name
75- * @param {any } dependencyOutput
76- * @param {Partial<GeneratorOptions> } extra
77- */
78- const runInWorker = ( name , dependencyOutput , extra ) => {
79- return new Promise ( ( resolve , reject ) => {
80- /**
81- * Run the generator
82- */
83- const run = ( ) => {
84- activeThreads ++ ;
85-
86- const worker = new Worker ( new URL ( import . meta. url ) , {
87- workerData : { name, dependencyOutput, extra } ,
88- } ) ;
89-
90- worker . on ( 'message' , result => {
91- activeThreads -- ;
92- processQueue ( ) ;
93-
94- if ( result && result . error ) {
95- reject ( result . error ) ;
96- } else {
97- resolve ( result ) ;
98- }
99- } ) ;
100-
101- worker . on ( 'error' , err => {
102- activeThreads -- ;
103- processQueue ( ) ;
104- reject ( err ) ;
105- } ) ;
106- } ;
107-
108- if ( activeThreads >= MAX_THREADS ) {
109- threadQueue . push ( run ) ;
110- } else {
111- run ( ) ;
112- }
113- } ) ;
114- } ;
115-
116- /**
117- * Process the worker thread queue
118- */
119- const processQueue = ( ) => {
120- if ( threadQueue . length > 0 && activeThreads < MAX_THREADS ) {
121- const next = threadQueue . shift ( ) ;
122- next ( ) ;
123- }
124- } ;
37+ const threadPool = new WorkerPool ( ) ;
12538
12639 /**
12740 * Runs the Generator engine with the provided top-level input and the given generator options
12841 *
12942 * @param {GeneratorOptions } options The options for the generator runtime
13043 */
131- const runGenerators = async ( {
132- generators,
133- disableParallelism = false ,
134- ...extra
135- } ) => {
44+ const runGenerators = async ( { generators, threads, ...extra } ) => {
13645 // Note that this method is blocking, and will only execute one generator per-time
13746 // but it ensures all dependencies are resolved, and that multiple bottom-level generators
13847 // can reuse the already parsed content from the top-level/dependency generators
@@ -141,14 +50,14 @@ const createGenerator = markdownInput => {
14150 dependsOn,
14251 generate,
14352 parallizable = true ,
144- } = availableGenerators [ generatorName ] ;
53+ } = allGenerators [ generatorName ] ;
14554
14655 // If the generator dependency has not yet been resolved, we resolve
14756 // the dependency first before running the current generator
14857 if ( dependsOn && ! ( dependsOn in cachedGenerators ) ) {
14958 await runGenerators ( {
15059 ...extra ,
151- disableParallelism ,
60+ threads ,
15261 generators : [ dependsOn ] ,
15362 } ) ;
15463 }
@@ -159,9 +68,9 @@ const createGenerator = markdownInput => {
15968
16069 // Adds the current generator execution Promise to the cache
16170 cachedGenerators [ generatorName ] =
162- disableParallelism || ! parallizable
71+ threads < 2 || ! parallizable
16372 ? generate ( dependencyOutput , extra ) // Run in main thread
164- : runInWorker ( generatorName , dependencyOutput , extra ) ; // Offload to worker thread
73+ : threadPool . run ( generatorName , dependencyOutput , threads , extra ) ; // Offload to worker thread
16574 }
16675
16776 // Returns the value of the last generator of the current pipeline
0 commit comments