@nxtedition/lib 26.0.27 → 26.0.29

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.
Files changed (2) hide show
  1. package/app.js +46 -39
  2. package/package.json +1 -1
package/app.js CHANGED
@@ -39,8 +39,7 @@ import undici from '@nxtedition/undici'
39
39
  import { isPrimary } from 'node:cluster'
40
40
  import { nice } from '@napi-rs/nice'
41
41
  import path from 'node:path'
42
-
43
- import { sched_setaffinity, sched_getaffinity } from '@nxtedition/sched'
42
+ import { sched_getaffinity, sched_setaffinity } from '@nxtedition/sched'
44
43
 
45
44
  export function makeApp(appConfig, onTerminate) {
46
45
  let ds
@@ -127,13 +126,17 @@ export function makeApp(appConfig, onTerminate) {
127
126
  const appDestroyers = []
128
127
 
129
128
  const serviceName = appConfig.name
130
- const serviceModule = appConfig.module ?? 'main'
131
129
  const serviceVersion = appConfig.version
130
+ const serviceModule = appConfig.module ?? 'main'
132
131
  const serviceWorkerId = appConfig.workerId ?? threadId
133
132
  const serviceInstanceId =
134
133
  // process.env.name is the pm2 name of the process
135
134
  appConfig.instanceId ?? appConfig.containerId ?? process.env.name ?? os.hostname()
136
135
 
136
+ if (!serviceName) {
137
+ throw new Error('Service name is required')
138
+ }
139
+
137
140
  const userAgent = (globalThis.userAgent =
138
141
  appConfig.userAgent ??
139
142
  (serviceName &&
@@ -313,50 +316,53 @@ export function makeApp(appConfig, onTerminate) {
313
316
  }
314
317
  }
315
318
 
316
- if (appConfig.affinity != null && process.platform === 'linux') {
317
- try {
318
- const nodes = []
319
- for (const entry of fs.readdirSync('/sys/devices/system/node')) {
320
- if (!entry.startsWith('node')) {
321
- continue
322
- }
319
+ let affinity = null
320
+ if (isMainThread && appConfig.affinity !== false && process.platform === 'linux') {
321
+ const allNodes = []
322
+ for (const entry of fs.readdirSync('/sys/devices/system/node')) {
323
+ if (!entry.startsWith('node')) {
324
+ continue
325
+ }
323
326
 
324
- const cpulist = fs
325
- .readFileSync(path.join('/sys/devices/system/node', entry, 'cpulist'), 'utf8')
326
- .trim()
327
- const cpus = []
328
- for (const part of cpulist.split(',')) {
329
- if (part.includes('-')) {
330
- const [start, end] = part.split('-').map(Number)
331
- for (let i = start; i <= end; i++) cpus.push(i)
332
- } else {
333
- cpus.push(Number(part))
327
+ const cpulist = fs
328
+ .readFileSync(path.join('/sys/devices/system/node', entry, 'cpulist'), 'utf8')
329
+ .trim()
330
+ const cpus = []
331
+ for (const part of cpulist.split(',')) {
332
+ if (part.includes('-')) {
333
+ const [start, end] = part.split('-').map(Number)
334
+ for (let i = start; i <= end; i++) {
335
+ cpus.push(i)
334
336
  }
337
+ } else {
338
+ cpus.push(Number(part))
335
339
  }
336
- nodes.push(cpus)
337
340
  }
341
+ allNodes.push(cpus)
342
+ }
338
343
 
339
- let indices
340
- if (typeof appConfig.affinity === 'number') {
341
- indices = [appConfig.affinity]
342
- } else if (Array.isArray(appConfig.affinity)) {
343
- indices = appConfig.affinity
344
- } else {
345
- indices = [Math.floor(Math.random() * nodes.length)]
346
- }
344
+ if (Number.isInteger(appConfig.affinity) && appConfig.affinity >= 0) {
345
+ affinity = allNodes[appConfig.affinity % allNodes.length]
346
+ } else if (appConfig.affinity == null) {
347
+ affinity = allNodes[hashString(serviceName) % allNodes.length]
348
+ } else {
349
+ throw new Error('invalid affinity configuration: ' + appConfig.affinity)
350
+ }
347
351
 
348
- if (indices?.length > 0) {
349
- let affinity = []
350
- for (const index of indices) {
351
- affinity = fp.union(affinity, nodes[index % nodes.length])
352
- }
352
+ affinity = fp.uniq(affinity)
353
+ affinity = fp.intersection(affinity, sched_getaffinity(0))
353
354
 
354
- const next = affinity
355
- const prev = sched_getaffinity(0)
355
+ if (
356
+ !Array.isArray(affinity) ||
357
+ affinity.length === 0 ||
358
+ affinity.some((x) => typeof x !== 'number' || x < 0)
359
+ ) {
360
+ throw new Error('invalid affinity configuration: ' + appConfig.affinity)
361
+ }
356
362
 
357
- sched_setaffinity(0, fp.intersection(prev, next))
358
- logger.debug({ data: { prev, next, nodes, affinity } }, 'sched_setaffinity succeeded')
359
- }
363
+ try {
364
+ sched_setaffinity(0, affinity)
365
+ logger.debug({ data: { value: appConfig.affinity, affinity } }, 'sched_setaffinity succeeded')
360
366
  } catch (err) {
361
367
  logger.error({ err }, 'sched_setaffinity failed')
362
368
  }
@@ -1327,5 +1333,6 @@ export function makeApp(appConfig, onTerminate) {
1327
1333
  serviceInstanceId,
1328
1334
  serviceWorkerId,
1329
1335
  signal: ac.signal,
1336
+ affinity,
1330
1337
  })
1331
1338
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "26.0.27",
3
+ "version": "26.0.29",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "type": "module",