创建命令
除了使用 Ace 命令,你也可以将自定义命令作为应用代码库的一部分来创建。命令存储在 commands 目录(位于根级别)。你可以通过运行以下命令来创建命令。
相关阅读:Make command
node ace make:command greet
上述命令会在 commands 目录中创建一个 greet.ts 文件。Ace 命令由一个类表示,并且必须实现 run 方法来执行命令逻辑。
命令元数据
命令元数据包含命令名称、描述、帮助文本,以及用于配置命令行为的选项。
import { BaseCommand } from '@adonisjs/core/ace'
import { CommandOptions } from '@adonisjs/core/types/ace'
export default class GreetCommand extends BaseCommand {
static commandName = 'greet'
static description = 'Greet a user by name'
static options: CommandOptions = {
startApp: false,
allowUnknownFlags: false,
staysAlive: false,
}
}
- commandName
-
commandName属性用于定义命令名称。命令名称不应包含空格。此外,建议避免在命令名称中使用*、&或不熟悉的斜杠等特殊的字符。命令名称可以位于某个命名空间之下。例如,要在
make命名空间下定义一个命令,可以在其前面加上make:。 - description
-
命令描述会显示在命令列表和命令帮助屏幕上。你必须保持描述简短,并使用帮助文本来书写更长的描述。
- help
-
帮助文本用于书写更长的描述或展示用法示例。
export default class GreetCommand extends BaseCommand {static help = ['The greet command is used to greet a user by name','','You can also send flowers to a user, if they have an updated address','{{ binaryName }} greet --send-flowers',]}{{ binaryName }}变量替换是对用于执行 ace 命令的二进制文件的引用。 - aliases
-
你可以使用
aliases属性为命令名称定义一个或多个别名。export default class GreetCommand extends BaseCommand {static commandName = 'greet'static aliases = ['welcome', 'sayhi']} - options.startApp
-
默认情况下,AdonisJS 在运行 Ace 命令时不会启动应用。这样可以确保命令运行快速,并且无需经过应用启动阶段即可执行简单任务。
但是,如果你的命令依赖应用状态,你可以告诉 Ace 在执行命令之前启动应用。
import { BaseCommand } from '@adonisjs/core/ace'import { CommandOptions } from '@adonisjs/core/types/ace'export default class GreetCommand extends BaseCommand {static options: CommandOptions = {startApp: true}} - options.allowUnknownFlags
-
默认情况下,如果你向命令传递了未知的标志,Ace 会打印错误。但是,你可以使用
options.allowUnknownFlags属性在命令级别禁用严格的标志解析。import { BaseCommand } from '@adonisjs/core/ace'import { CommandOptions } from '@adonisjs/core/types/ace'export default class GreetCommand extends BaseCommand {static options: CommandOptions = {allowUnknownFlags: true}} - options.staysAlive
-
AdonisJS 会在执行完命令的
run命令后隐式终止应用。但是,如果你想在命令中启动一个长时间运行的进程,就必须告诉 Ace 不要杀死该进程。import { BaseCommand } from '@adonisjs/core/ace'import { CommandOptions } from '@adonisjs/core/types/ace'export default class GreetCommand extends BaseCommand {static options: CommandOptions = {staysAlive: true}}
命令生命周期方法
你可以在一个命令类上定义以下生命周期方法,Ace 会按照预定义的顺序执行它们。
import { BaseCommand, args, flags } from '@adonisjs/core/ace'
export default class GreetCommand extends BaseCommand {
async prepare() {
console.log('preparing')
}
async interact() {
console.log('interacting')
}
async run() {
console.log('running')
}
async completed() {
console.log('completed')
}
}
| 方法 | 描述 |
|---|---|
prepare
|
这是 Ace 在命令上执行的第一个方法。此方法可以设置运行命令所需的状态或数据。 |
interact
|
interact 方法在 prepare 方法之后执行。它可以用于向用户显示交互提示。 |
run
|
命令的主要逻辑放在 run 方法中。此方法在 interact 方法之后被调用。 |
completed
|
completed 方法在运行完所有其他生命周期方法后被调用。此方法可以用于执行清理,或处理/展示其他方法抛出的异常。 |
依赖注入
Ace 命令是通过 IoC 容器 构建和执行的。因此,你可以在命令的生命周期方法上标注依赖类型提示,并使用 @inject 装饰器来解析它们。
为了演示,让我们将 UserService 类注入到所有生命周期方法中。
import { inject } from '@adonisjs/core'
import { BaseCommand } from '@adonisjs/core/ace'
import UserService from '#services/user_service'
export default class GreetCommand extends BaseCommand {
@inject()
async prepare(userService: UserService) {
}
@inject()
async interact(userService: UserService) {
}
@inject()
async run(userService: UserService) {
}
@inject()
async completed(userService: UserService) {
}
}
处理错误与退出码
命令抛出的异常会通过 CLI 日志记录器显示,并且命令的 exitCode 会被设置为 1(非零错误码表示命令执行失败)。
不过,你也可以通过将代码包裹在 try/catch 块中,或使用 completed 生命周期方法来捕获错误。在这两种情况下,记得更新命令的 exitCode 和 error 属性。
使用 try/catch 处理错误
import { BaseCommand } from '@adonisjs/core/ace'
export default class GreetCommand extends BaseCommand {
async run() {
try {
await runSomeOperation()
} catch (error) {
this.logger.error(error.message)
this.error = error
this.exitCode = 1
}
}
}
在 completed 方法中处理错误
import { BaseCommand } from '@adonisjs/core/ace'
export default class GreetCommand extends BaseCommand {
async run() {
await runSomeOperation()
}
async completed() {
if (this.error) {
this.logger.error(this.error.message)
/**
* 通知 Ace 错误已被处理
*/
return true
}
}
}
终止应用
默认情况下,Ace 会在执行完命令后终止应用。但是,如果你启用了 staysAlive 选项,就必须使用 this.terminate 方法显式终止应用。
假设我们建立一个 redis 连接来监控服务器内存。我们监听 redis 连接上的 error 事件,并在连接失败时终止应用。
import { BaseCommand } from '@adonisjs/core/ace'
import { CommandOptions } from '@adonisjs/core/types/ace'
export default class GreetCommand extends BaseCommand {
static options: CommandOptions = {
staysAlive: true
}
async run() {
const redis = createRedisConnection()
redis.on('error', (error) => {
this.logger.error(error)
this.terminate()
})
}
}
在应用终止前进行清理
多个事件都可能触发应用终止,包括 SIGTERM 信号。因此,你必须在命令中监听 terminating 钩子来执行清理工作。
你可以在 prepare 生命周期方法中监听 terminating 钩子。
import { BaseCommand } from '@adonisjs/core/ace'
import { CommandOptions } from '@adonisjs/core/types/ace'
export default class GreetCommand extends BaseCommand {
static options: CommandOptions = {
staysAlive: true
}
prepare() {
this.app.terminating(() => {
// 执行清理
})
}
async run() {
}
}