import * as cluster from "cluster" ; import * as process from "process" ; import * as _ from "lodash" ; const exit = require ( "exit" ) ; const WORKERS = [ "👷🏻" , "👷🏼" , "👷🏽" , "👷🏾" , "👷🏿" ] ; export interface ParallelArgs < Item , Result , Acc > { queue : Item [ ] ; workers : number ; setup ( ) : Promise < Acc > ; map ( item , index ) : Promise < Result > ; } function randomPick < T > ( arr ) { return arr [ Math . floor ( Math . random ( ) * arr . length ) ] ; } function guys ( n ) { return _ . range ( n ) . map ( _i => randomPick ( WORKERS ) ) . join ( " " ) ; } export async function inParallel < Item , Result , Acc > ( args ) { let { queue } = args ; let items = queue . map ( ( item , i ) => { return { item , i } ; } ) ; if ( cluster . isMaster ) { let { setup , workers , map } = args ; await setup ( ) ; cluster . on ( "message" , worker => { if ( items . length ) { worker . send ( items . shift ( ) ) ; } else { worker . kill ( ) ; } } ) ; cluster . on ( "exit" , ( _worker , code , _signal ) => { if ( code && code !== 0 ) { _ . forIn ( cluster . workers , w => { if ( w ) { w . kill ( ) ; } } ) ; exit ( code ) ; } } ) ; console . error ( `* Forking ${ workers } workers ${ guys ( workers ) }` ) ; if ( workers < 2 ) { for ( let { item , i } of items ) { await map ( item , i ) ; } } else { _ . range ( workers ) . forEach ( i => cluster . fork ( { worker : i , TS_NODE_PROJECT : "test/tsconfig.json" } ) ) ; } } else { let { map } = args ; process . on ( "message" , async ( { item , i } ) => { ( process . send as any ) ( { result : await map ( item , i ) } ) ; } ) ; ( process . send as any ) ( "ready" ) ; } }