ante-erp-cli 1.11.49 → 1.11.50
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.
package/package.json
CHANGED
package/src/commands/install.js
CHANGED
|
@@ -15,6 +15,7 @@ import { generateDockerCompose } from '../templates/docker-compose.yml.js';
|
|
|
15
15
|
import { generateEnv } from '../templates/env.js';
|
|
16
16
|
import { detectPublicIPWithFeedback, buildURL } from '../utils/network.js';
|
|
17
17
|
import { configureNginx, requiresNginx } from '../utils/nginx.js';
|
|
18
|
+
import { applySysctlSettings } from '../utils/system-config.js';
|
|
18
19
|
|
|
19
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
21
|
const __dirname = dirname(__filename);
|
|
@@ -302,6 +303,10 @@ export async function install(options) {
|
|
|
302
303
|
}
|
|
303
304
|
|
|
304
305
|
console.log(chalk.green(`✓ ${formatStepTitle(stepSystemCheck, totalSteps, 'System requirements met')}\n`));
|
|
306
|
+
|
|
307
|
+
// Configure system kernel parameters for Redis
|
|
308
|
+
console.log(chalk.cyan(' Configuring system kernel parameters...'));
|
|
309
|
+
await applySysctlSettings();
|
|
305
310
|
}
|
|
306
311
|
|
|
307
312
|
// Step: Network detection
|
package/src/commands/update.js
CHANGED
|
@@ -9,6 +9,7 @@ import { backup } from './backup.js';
|
|
|
9
9
|
import { getCurrentVersion, getLatestVersion } from './update-cli.js';
|
|
10
10
|
import { generateDockerCompose } from '../templates/docker-compose.yml.js';
|
|
11
11
|
import { generateSecurePassword } from '../utils/password.js';
|
|
12
|
+
import { verifySysctlSettings, applySysctlSettings } from '../utils/system-config.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Check if gate-app, guardian-app, facial-web, or pos-app is installed by checking docker-compose.yml
|
|
@@ -461,6 +462,16 @@ export async function update(options) {
|
|
|
461
462
|
refreshDockerCompose(composeFile, envFile);
|
|
462
463
|
}
|
|
463
464
|
|
|
465
|
+
// Verify and apply sysctl settings if needed (for Redis optimization)
|
|
466
|
+
console.log(chalk.gray('Verifying system kernel parameters...'));
|
|
467
|
+
const sysctlCheck = await verifySysctlSettings();
|
|
468
|
+
if (!sysctlCheck.ok) {
|
|
469
|
+
console.log(chalk.yellow(' Reapplying system kernel parameters...'));
|
|
470
|
+
await applySysctlSettings();
|
|
471
|
+
} else {
|
|
472
|
+
console.log(chalk.gray(' System kernel parameters OK'));
|
|
473
|
+
}
|
|
474
|
+
|
|
464
475
|
// Pre-calculate step numbers for each task (fixes step numbering bug)
|
|
465
476
|
let currentStep = 0;
|
|
466
477
|
const stepPreStart = !options.skipBackup ? ++currentStep : null;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import { writeFileSync } from 'fs';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
const SYSCTL_CONFIG_FILE = '/etc/sysctl.d/ante-redis.conf';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Required sysctl settings for optimal Redis performance
|
|
9
|
+
* vm.overcommit_memory=1 prevents Redis background save failures under low memory
|
|
10
|
+
*/
|
|
11
|
+
const REQUIRED_SETTINGS = {
|
|
12
|
+
'vm.overcommit_memory': '1'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check if a sysctl setting is currently applied
|
|
17
|
+
* @param {string} key - The sysctl key (e.g., 'vm.overcommit_memory')
|
|
18
|
+
* @returns {Promise<string|null>} Current value or null if error
|
|
19
|
+
*/
|
|
20
|
+
export async function checkSysctlSetting(key) {
|
|
21
|
+
try {
|
|
22
|
+
const { stdout } = await execa('sysctl', ['-n', key]);
|
|
23
|
+
return stdout.trim();
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Apply a sysctl setting immediately
|
|
31
|
+
* @param {string} key - The sysctl key
|
|
32
|
+
* @param {string} value - The value to set
|
|
33
|
+
* @returns {Promise<boolean>} Success status
|
|
34
|
+
*/
|
|
35
|
+
export async function applySysctlSetting(key, value) {
|
|
36
|
+
try {
|
|
37
|
+
await execa('sudo', ['sysctl', '-w', `${key}=${value}`], { stdio: 'pipe' });
|
|
38
|
+
return true;
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Persist sysctl settings to config file for reboot survival
|
|
46
|
+
* @returns {Promise<boolean>} Success status
|
|
47
|
+
*/
|
|
48
|
+
export async function persistSysctlSettings() {
|
|
49
|
+
const lines = Object.entries(REQUIRED_SETTINGS)
|
|
50
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
51
|
+
.join('\n');
|
|
52
|
+
|
|
53
|
+
const content = `# ANTE ERP Redis Optimization
|
|
54
|
+
# Generated by ante-erp-cli
|
|
55
|
+
# See: https://redis.io/docs/getting-started/faq/#background-saving-fails-with-a-fork-error-on-linux
|
|
56
|
+
${lines}
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
// Write to temp file then move with sudo
|
|
61
|
+
const tempFile = '/tmp/ante-sysctl.conf';
|
|
62
|
+
writeFileSync(tempFile, content);
|
|
63
|
+
await execa('sudo', ['mv', tempFile, SYSCTL_CONFIG_FILE], { stdio: 'pipe' });
|
|
64
|
+
await execa('sudo', ['chmod', '644', SYSCTL_CONFIG_FILE], { stdio: 'pipe' });
|
|
65
|
+
return true;
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Apply and persist all required sysctl settings
|
|
73
|
+
* @param {boolean} silent - Suppress console output
|
|
74
|
+
* @returns {Promise<{applied: string[], failed: string[], skipped: string[]}>}
|
|
75
|
+
*/
|
|
76
|
+
export async function applySysctlSettings(silent = false) {
|
|
77
|
+
const results = { applied: [], failed: [], skipped: [] };
|
|
78
|
+
|
|
79
|
+
for (const [key, value] of Object.entries(REQUIRED_SETTINGS)) {
|
|
80
|
+
const current = await checkSysctlSetting(key);
|
|
81
|
+
|
|
82
|
+
if (current === value) {
|
|
83
|
+
results.skipped.push(key);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const success = await applySysctlSetting(key, value);
|
|
88
|
+
if (success) {
|
|
89
|
+
results.applied.push(key);
|
|
90
|
+
} else {
|
|
91
|
+
results.failed.push(key);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Persist to config file for reboot survival
|
|
96
|
+
if (results.applied.length > 0) {
|
|
97
|
+
await persistSysctlSettings();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!silent) {
|
|
101
|
+
if (results.applied.length > 0) {
|
|
102
|
+
console.log(chalk.green(` ✓ Applied sysctl settings: ${results.applied.join(', ')}`));
|
|
103
|
+
}
|
|
104
|
+
if (results.skipped.length > 0) {
|
|
105
|
+
console.log(chalk.gray(` Sysctl settings already configured: ${results.skipped.join(', ')}`));
|
|
106
|
+
}
|
|
107
|
+
if (results.failed.length > 0) {
|
|
108
|
+
console.log(chalk.yellow(` ⚠ Failed to apply: ${results.failed.join(', ')} (may require root privileges)`));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return results;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Verify sysctl settings are applied (for update command)
|
|
117
|
+
* @returns {Promise<{ok: boolean, missing: Array<{key: string, expected: string, current: string|null}>}>}
|
|
118
|
+
*/
|
|
119
|
+
export async function verifySysctlSettings() {
|
|
120
|
+
const missing = [];
|
|
121
|
+
|
|
122
|
+
for (const [key, value] of Object.entries(REQUIRED_SETTINGS)) {
|
|
123
|
+
const current = await checkSysctlSetting(key);
|
|
124
|
+
if (current !== value) {
|
|
125
|
+
missing.push({ key, expected: value, current });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return { ok: missing.length === 0, missing };
|
|
130
|
+
}
|