Skip to content

Commit

Permalink
f
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Dec 31, 2024
1 parent a238b50 commit b9fe64d
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 336 deletions.
116 changes: 0 additions & 116 deletions src/command.js

This file was deleted.

75 changes: 0 additions & 75 deletions src/commands/stop.js

This file was deleted.

100 changes: 100 additions & 0 deletions src/commands/stop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { debuglog, format } from 'node:util';
import { scheduler } from 'node:timers/promises';
import { Args, Flags } from '@oclif/core';
import { BaseCommand } from '../baseCommand.js';
import { isWindows, findNodeProcess, NodeProcess, kill } from '../helper.js';

const debug = debuglog('@eggjs/scripts/commands/stop');

const osRelated = {
titleTemplate: isWindows ? '\\"title\\":\\"%s\\"' : '"title":"%s"',
// node_modules/@eggjs/cluster/dist/commonjs/app_worker.js
// node_modules/@eggjs/cluster/dist/esm/app_worker.js
appWorkerPath: /@eggjs[\/\\]cluster[\/\\]dist[\/\\](commonjs|esm)[\/\\]app_worker\.js/i,
// node_modules/@eggjs/cluster/dist/commonjs/agent_worker.js
// node_modules/@eggjs/cluster/dist/esm/agent_worker.js
agentWorkerPath: /@eggjs[\/\\]cluster[\/\\]dist[\/\\](commonjs|esm)[\/\\]agent_worker\.js/i,
};

export default class Stop<T extends typeof Stop> extends BaseCommand<T> {
static override description = 'Stop server';

static override examples = [
'<%= config.bin %> <%= command.id %>',
];

static override args = {
baseDir: Args.string({
description: 'directory of application',
required: false,
}),
};

static override flags = {
title: Flags.string({
description: 'process title description, use for kill grep',
}),
timeout: Flags.integer({
description: 'the maximum timeout(ms) when app stop',
default: 5000,
}),
};

public async run(): Promise<void> {
const { flags } = this;

this.log(`stopping egg application${flags.title ? ` with --title=${flags.title}` : ''}`);

// node ~/eggjs/scripts/scripts/start-cluster.cjs {"title":"egg-server","workers":4,"port":7001,"baseDir":"~/eggjs/test/showcase","framework":"~/eggjs/test/showcase/node_modules/egg"}
let processList = await this.findNodeProcesses(item => {
const cmd = item.cmd;
const matched = flags.title ?
cmd.includes('start-cluster') && cmd.includes(format(osRelated.titleTemplate, flags.title)) :
cmd.includes('start-cluster');
if (matched) {
debug('find master process: %o', item);
}
return matched;
});
let pids = processList.map(x => x.pid);

if (pids.length) {
this.log('got master pid %j', pids);
this.killProcesses(pids);
// wait for 5s to confirm whether any worker process did not kill by master
await scheduler.wait(flags.timeout);
} else {
this.logToStderr('can\'t detect any running egg process');
}

// node --debug-port=5856 /Users/tz/Workspaces/eggjs/test/showcase/node_modules/[email protected]@egg-cluster/lib/agent_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406}
// node /Users/tz/Workspaces/eggjs/test/showcase/node_modules/[email protected]@egg-cluster/lib/app_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406}
// ~/bin/node --no-deprecation --trace-warnings ~/eggjs/examples/helloworld/node_modules/@eggjs/cluster/dist/commonjs/agent_worker.js {"baseDir":"~/eggjs/examples/helloworld","startMode":"process","framework":"~/eggjs/examples/helloworld/node_modules/egg","title":"egg-server-helloworld","workers":10,"clusterPort":58977}
processList = await this.findNodeProcesses(item => {
const cmd = item.cmd;
const matched = flags.title ?
(osRelated.appWorkerPath.test(cmd) || osRelated.agentWorkerPath.test(cmd)) && cmd.includes(format(osRelated.titleTemplate, flags.title)) :
(osRelated.appWorkerPath.test(cmd) || osRelated.agentWorkerPath.test(cmd));
if (matched) {
debug('find app/agent worker process: %o', item);
}
return matched;
});
pids = processList.map(x => x.pid);

if (pids.length) {
this.log('got worker/agent pids %j that is not killed by master', pids);
this.killProcesses(pids);
}

this.log('stopped');
}

protected async findNodeProcesses(filter: (item: NodeProcess) => boolean): Promise<NodeProcess[]> {
return findNodeProcess(filter);
}

protected killProcesses(pids: number[], signal: NodeJS.Signals = 'SIGTERM') {
kill(pids, signal);
}
}
8 changes: 3 additions & 5 deletions test/fixtures/stop-timeout/app/router.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
'use strict';

module.exports = app => {
app.get('/', function* () {
app.get('/', async function() {
this.body = `hi, ${app.config.framework || 'egg'}`;
});

app.get('/env', function* () {
app.get('/env', async function() {
this.body = app.config.env + ', ' + app.config.pre;
});

app.get('/path', function* () {
app.get('/path', async function() {
this.body = process.env.PATH;
});
};
7 changes: 2 additions & 5 deletions test/start.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,19 @@ import { fileURLToPath } from 'node:url';
import { strict as assert } from 'node:assert';
import fs from 'node:fs/promises';
import { scheduler } from 'node:timers/promises';
import { ChildProcess } from 'node:child_process';
import { createServer } from 'node:http';
import { once } from 'node:events';
import coffee, { Coffee as _Coffee } from 'coffee';
import coffee from 'coffee';
import { request } from 'urllib';
import { mm, restore } from 'mm';
import { exists } from 'utility';
import { cleanup, replaceWeakRefMessage } from './utils.js';
import { cleanup, replaceWeakRefMessage, Coffee } from './utils.js';
import { isWindows, getSourceFilename } from '../src/helper.js';

const version = parseInt(process.version.split('.')[0].substring(1));
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

type Coffee = _Coffee & { proc: ChildProcess, stderr: string, stdout: string, code?: number };

describe('test/start.test.ts', () => {
const eggBin = getSourceFilename('../bin/run.js');
const fixturePath = path.join(__dirname, 'fixtures/example');
Expand Down
Loading

0 comments on commit b9fe64d

Please sign in to comment.