93 lines
3.3 KiB
JavaScript
93 lines
3.3 KiB
JavaScript
|
|
const { Client } = require('ssh2');
|
|||
|
|
const SSH_CONFIG = { host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' };
|
|||
|
|
|
|||
|
|
function sshExec(conn, cmd) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
conn.exec(cmd, (err, s) => {
|
|||
|
|
if (err) return reject(err);
|
|||
|
|
let o = '';
|
|||
|
|
s.on('data', d => o += d);
|
|||
|
|
s.stderr.on('data', d => o += d);
|
|||
|
|
s.on('close', () => resolve(o));
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
|
|||
|
|
function sftpUpload(conn, localPath, remotePath) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
conn.sftp((err, sftp) => {
|
|||
|
|
if (err) return reject(err);
|
|||
|
|
const rs = fs.createReadStream(localPath);
|
|||
|
|
const ws = sftp.createWriteStream(remotePath);
|
|||
|
|
ws.on('close', () => resolve());
|
|||
|
|
ws.on('error', reject);
|
|||
|
|
rs.pipe(ws);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const REMOTE_BASE = '/www/wwwroot/demo.tensorgrove.com.cn/server';
|
|||
|
|
const LOCAL_BASE = path.join(__dirname, '..');
|
|||
|
|
|
|||
|
|
async function main() {
|
|||
|
|
const conn = new Client();
|
|||
|
|
await new Promise((resolve, reject) => {
|
|||
|
|
conn.on('ready', resolve).on('error', reject).connect(SSH_CONFIG);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 1. 上传文件
|
|||
|
|
const files = [
|
|||
|
|
{ name: 'toolExecutor.js', sub: 'services' },
|
|||
|
|
{ name: 'kbRetriever.js', sub: 'services' },
|
|||
|
|
];
|
|||
|
|
console.log('=== 上传 ===');
|
|||
|
|
for (const f of files) {
|
|||
|
|
const localFile = path.join(LOCAL_BASE, f.sub, f.name);
|
|||
|
|
const remoteFile = `${REMOTE_BASE}/${f.sub}/${f.name}`;
|
|||
|
|
await sftpUpload(conn, localFile, remoteFile);
|
|||
|
|
console.log(` \u2705 ${f.name}`);
|
|||
|
|
const sc = await sshExec(conn, `node -c ${remoteFile} 2>&1`);
|
|||
|
|
if (sc.includes('SyntaxError')) { console.log('SYNTAX ERROR!'); conn.end(); process.exit(1); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 刷 Redis KB 缓存
|
|||
|
|
console.log('\n=== 刷 Redis KB 缓存 ===');
|
|||
|
|
console.log(await sshExec(conn, `cd ${REMOTE_BASE} && node -e "
|
|||
|
|
require('dotenv').config();
|
|||
|
|
const Redis = require('ioredis');
|
|||
|
|
const r = new Redis(process.env.REDIS_URL || 'redis://127.0.0.1:6379', {
|
|||
|
|
password: process.env.REDIS_PASSWORD || undefined,
|
|||
|
|
db: parseInt(process.env.REDIS_DB) || 0,
|
|||
|
|
keyPrefix: process.env.REDIS_KEY_PREFIX || 'bigwo:',
|
|||
|
|
lazyConnect: true, maxRetriesPerRequest: 2, connectTimeout: 5000,
|
|||
|
|
});
|
|||
|
|
r.connect().then(async () => {
|
|||
|
|
const keys = await r.keys('kb_cache:*');
|
|||
|
|
if (keys.length > 0) { await r.del(...keys); console.log('Deleted ' + keys.length + ' keys'); }
|
|||
|
|
else { console.log('No keys'); }
|
|||
|
|
r.quit(); process.exit(0);
|
|||
|
|
}).catch(e => { console.log('Redis: ' + e.message); process.exit(0); });
|
|||
|
|
" 2>&1`));
|
|||
|
|
|
|||
|
|
// 3. 重启
|
|||
|
|
await sshExec(conn, '> /var/log/bigwo/server-error.log && > /var/log/bigwo/server-out.log');
|
|||
|
|
await sshExec(conn, 'pm2 stop bigwo-server');
|
|||
|
|
await new Promise(r => setTimeout(r, 1000));
|
|||
|
|
await sshExec(conn, `cd ${REMOTE_BASE} && pm2 start bigwo-server --update-env`);
|
|||
|
|
console.log('\n=== PM2 重启,等待5s ===');
|
|||
|
|
await new Promise(r => setTimeout(r, 5000));
|
|||
|
|
console.log(await sshExec(conn, 'pm2 status bigwo-server'));
|
|||
|
|
const errLog = await sshExec(conn, 'cat /var/log/bigwo/server-error.log');
|
|||
|
|
console.log('=== 错误 ===');
|
|||
|
|
console.log(errLog || '(空 ✅)');
|
|||
|
|
console.log('\n=== 健康 ===');
|
|||
|
|
console.log(await sshExec(conn, 'curl -s --max-time 5 http://localhost:3012/api/health 2>&1'));
|
|||
|
|
|
|||
|
|
conn.end();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main().catch(e => { console.error('FAILED:', e.message); process.exit(1); });
|