@@ -45,6 +45,7 @@ import {
4545 checkValidPriority ,
4646 checkValidTasksQueueOptions ,
4747 checkValidWorkerChoiceStrategy ,
48+ checkValidWorkerNodeKeys ,
4849 getDefaultTasksQueueOptions ,
4950 updateEluWorkerUsage ,
5051 updateRunTimeWorkerUsage ,
@@ -842,8 +843,8 @@ export abstract class AbstractPool<
842843 private async sendTaskFunctionOperationToWorkers (
843844 message : MessageValue < Data > ,
844845 ) : Promise < boolean > {
845- const targetWorkerNodeKeys = [ ... this . workerNodes . keys ( ) ]
846- if ( targetWorkerNodeKeys . length === 0 ) {
846+ const targetWorkerNodeCount = this . workerNodes . length
847+ if ( targetWorkerNodeCount === 0 ) {
847848 return true
848849 }
849850 const responsesReceived : MessageValue < Response > [ ] = [ ]
@@ -853,14 +854,14 @@ export abstract class AbstractPool<
853854 reject : ( reason ?: unknown ) => void ,
854855 ) : void => {
855856 this . checkMessageWorkerId ( message )
857+ const workerNodeKey = this . getWorkerNodeKeyByWorkerId ( message . workerId )
856858 if (
857859 message . taskFunctionOperationStatus != null &&
858- targetWorkerNodeKeys . includes (
859- this . getWorkerNodeKeyByWorkerId ( message . workerId ) ,
860- )
860+ workerNodeKey >= 0 &&
861+ workerNodeKey < targetWorkerNodeCount
861862 ) {
862863 responsesReceived . push ( message )
863- if ( responsesReceived . length >= targetWorkerNodeKeys . length ) {
864+ if ( responsesReceived . length >= targetWorkerNodeCount ) {
864865 if (
865866 responsesReceived . every (
866867 ( msg ) => msg . taskFunctionOperationStatus === true ,
@@ -883,19 +884,20 @@ export abstract class AbstractPool<
883884 }
884885 }
885886 let listener : ( ( message : MessageValue < Response > ) => void ) | undefined
887+ const workerNodeKeys = [ ...this . workerNodes . keys ( ) ]
886888 try {
887889 return await new Promise < boolean > ( ( resolve , reject ) => {
888890 listener = ( message : MessageValue < Response > ) => {
889891 taskFunctionOperationsListener ( message , resolve , reject )
890892 }
891- for ( const workerNodeKey of targetWorkerNodeKeys ) {
893+ for ( const workerNodeKey of workerNodeKeys ) {
892894 this . registerWorkerMessageListener ( workerNodeKey , listener )
893895 this . sendToWorker ( workerNodeKey , message )
894896 }
895897 } )
896898 } finally {
897899 if ( listener != null ) {
898- for ( const workerNodeKey of targetWorkerNodeKeys ) {
900+ for ( const workerNodeKey of workerNodeKeys ) {
899901 this . deregisterWorkerMessageListener ( workerNodeKey , listener )
900902 }
901903 }
@@ -928,6 +930,10 @@ export abstract class AbstractPool<
928930 }
929931 checkValidPriority ( fn . priority )
930932 checkValidWorkerChoiceStrategy ( fn . strategy )
933+ checkValidWorkerNodeKeys (
934+ fn . workerNodeKeys ,
935+ this . maximumNumberOfWorkers ?? this . minimumNumberOfWorkers ,
936+ )
931937 const opResult = await this . sendTaskFunctionOperationToWorkers ( {
932938 taskFunctionOperation : 'add' ,
933939 taskFunctionProperties : buildTaskFunctionProperties ( name , fn ) ,
@@ -1057,6 +1063,26 @@ export abstract class AbstractPool<
10571063 ) ?. strategy
10581064 }
10591065
1066+ /**
1067+ * Gets task function worker node keys affinity set, if any.
1068+ * @param name - The task function name.
1069+ * @returns The task function worker node keys affinity set, or `undefined` if not defined.
1070+ */
1071+ private readonly getTaskFunctionWorkerNodeKeysSet = (
1072+ name ?: string ,
1073+ ) : ReadonlySet < number > | undefined => {
1074+ name = name ?? DEFAULT_TASK_NAME
1075+ const taskFunctionsProperties = this . listTaskFunctionsProperties ( )
1076+ if ( name === DEFAULT_TASK_NAME ) {
1077+ name = taskFunctionsProperties [ 1 ] ?. name
1078+ }
1079+ const workerNodeKeys = taskFunctionsProperties . find (
1080+ ( taskFunctionProperties : TaskFunctionProperties ) =>
1081+ taskFunctionProperties . name === name ,
1082+ ) ?. workerNodeKeys
1083+ return workerNodeKeys != null ? new Set ( workerNodeKeys ) : undefined
1084+ }
1085+
10601086 /**
10611087 * Gets worker node task function priority, if any.
10621088 *
@@ -1549,7 +1575,20 @@ export abstract class AbstractPool<
15491575 * @returns The chosen worker node key.
15501576 */
15511577 private chooseWorkerNode ( name ?: string ) : number {
1552- if ( this . shallCreateDynamicWorker ( ) ) {
1578+ const workerNodeKeysSet = this . getTaskFunctionWorkerNodeKeysSet ( name )
1579+ if ( workerNodeKeysSet != null ) {
1580+ const maxPoolSize = this . maximumNumberOfWorkers ??
1581+ this . minimumNumberOfWorkers
1582+ const targetSize = max ( ...workerNodeKeysSet ) + 1
1583+ while (
1584+ this . started &&
1585+ ! this . destroying &&
1586+ this . workerNodes . length < targetSize &&
1587+ this . workerNodes . length < maxPoolSize
1588+ ) {
1589+ this . createAndSetupDynamicWorkerNode ( )
1590+ }
1591+ } else if ( this . shallCreateDynamicWorker ( ) ) {
15531592 const workerNodeKey = this . createAndSetupDynamicWorkerNode ( )
15541593 if (
15551594 this . workerChoiceStrategiesContext ?. getPolicy ( ) . dynamicWorkerUsage ===
@@ -1560,6 +1599,7 @@ export abstract class AbstractPool<
15601599 }
15611600 return this . workerChoiceStrategiesContext ! . execute (
15621601 this . getTaskFunctionWorkerChoiceStrategy ( name ) ,
1602+ workerNodeKeysSet ,
15631603 )
15641604 }
15651605
@@ -2172,6 +2212,14 @@ export abstract class AbstractPool<
21722212 if ( ready == null || ! ready ) {
21732213 throw new Error ( `Worker ${ workerId ?. toString ( ) } failed to initialize` )
21742214 }
2215+ const maxPoolSize = this . maximumNumberOfWorkers ??
2216+ this . minimumNumberOfWorkers
2217+ for ( const taskFunctionProperties of taskFunctionsProperties ?? [ ] ) {
2218+ checkValidWorkerNodeKeys (
2219+ taskFunctionProperties . workerNodeKeys ,
2220+ maxPoolSize ,
2221+ )
2222+ }
21752223 const workerNodeKey = this . getWorkerNodeKeyByWorkerId ( workerId )
21762224 const workerNode = this . workerNodes [ workerNodeKey ]
21772225 workerNode . info . ready = ready
0 commit comments