@@ -26,6 +26,32 @@ const EVERY_SIXTH_HOUR = "0 */6 * * *"
2626const CRON_SCHEDULE = EVERY_SIXTH_HOUR
2727const INSTRUMENTATION_FILE = "instrumentation"
2828
29+ function parseValueOrPercentage ( value : string , base : number ) : number {
30+ if ( typeof value !== "string" ) {
31+ throw new Error ( `Invalid value: ${ value } . Must be a string.` )
32+ }
33+
34+ const trimmed = value . trim ( )
35+ if ( trimmed . endsWith ( "%" ) ) {
36+ const percent = parseFloat ( trimmed . slice ( 0 , - 1 ) )
37+ if ( isNaN ( percent ) ) {
38+ throw new Error ( `Invalid percentage: ${ value } ` )
39+ }
40+ if ( percent < 0 || percent > 100 ) {
41+ throw new Error ( `Percentage must be between 0 and 100: ${ value } ` )
42+ }
43+ return Math . round ( ( percent / 100 ) * base )
44+ } else {
45+ const num = parseInt ( trimmed , 10 )
46+ if ( isNaN ( num ) || num < 0 ) {
47+ throw new Error (
48+ `Invalid number: ${ value } . Must be a non-negative integer.`
49+ )
50+ }
51+ return num
52+ }
53+ }
54+
2955/**
3056 * Imports the "instrumentation.js" file from the root of the
3157 * directory and invokes the register function. The existence
@@ -142,9 +168,30 @@ async function start(args: {
142168 host ?: string
143169 port ?: number
144170 types ?: boolean
145- cluster ?: number
171+ cluster ?: string
172+ workers ?: string
173+ servers ?: string
146174} ) {
147- const { port = 9000 , host, directory, types } = args
175+ const {
176+ port = 9000 ,
177+ host,
178+ directory,
179+ types,
180+ cluster : clusterSize ,
181+ workers,
182+ servers,
183+ } = args
184+
185+ const maxCpus = os . cpus ( ) . length
186+ const clusterSizeNum = clusterSize
187+ ? parseValueOrPercentage ( clusterSize , maxCpus )
188+ : maxCpus
189+ const serversCount = servers
190+ ? parseValueOrPercentage ( servers , clusterSizeNum )
191+ : 0
192+ const workersCount = workers
193+ ? parseValueOrPercentage ( workers , clusterSizeNum )
194+ : 0
148195
149196 async function internalStart ( generateTypes : boolean ) {
150197 track ( "CLI_START" )
@@ -261,21 +308,32 @@ async function start(args: {
261308 * cluster mode
262309 */
263310 if ( "cluster" in args ) {
264- const maxCpus = os . cpus ( ) . length
265- const cpus = args . cluster ?? maxCpus
311+ const cpus = clusterSizeNum
312+ const numCPUs = Math . min ( maxCpus , cpus )
313+
314+ if ( serversCount + workersCount > numCPUs ) {
315+ throw new Error (
316+ `Sum of servers (${ serversCount } ) and workers (${ workersCount } ) cannot exceed cluster size (${ numCPUs } )`
317+ )
318+ }
266319
267320 if ( cluster . isPrimary ) {
268321 let isShuttingDown = false
269- const numCPUs = Math . min ( maxCpus , cpus )
270322 const killMainProccess = ( ) => process . exit ( 0 )
271323 const gracefulShutDown = ( ) => {
272324 isShuttingDown = true
273325 }
274326
275327 for ( let index = 0 ; index < numCPUs ; index ++ ) {
276328 const worker = cluster . fork ( )
329+ let workerMode : "server" | "worker" | "shared" = "shared"
330+ if ( index < serversCount ) {
331+ workerMode = "server"
332+ } else if ( index < serversCount + workersCount ) {
333+ workerMode = "worker"
334+ }
277335 worker . on ( "online" , ( ) => {
278- worker . send ( { index } )
336+ worker . send ( { index, workerMode } )
279337 } )
280338 }
281339
@@ -291,6 +349,10 @@ async function start(args: {
291349 process . on ( "SIGINT" , gracefulShutDown )
292350 } else {
293351 process . on ( "message" , async ( msg : any ) => {
352+ if ( msg . workerMode ) {
353+ process . env . MEDUSA_WORKER_MODE = msg . workerMode
354+ }
355+
294356 if ( msg . index > 0 ) {
295357 process . env . PLUGIN_ADMIN_UI_SKIP_CACHE = "true"
296358 }
0 commit comments