创建命令

创建命令

除了使用 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 = '通过名字问候用户'
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 不要终止该过程。

另请参阅:Terminating appcleaning up before the app terminates 部分。

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 prepare 方法之后执行 interact 方法。它可以用于向用户显示提示。
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 生命周期方法来处理错误。在这两种情况下,请记得更新命令的 exitCodeerror 属性。

使用 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() {
}
}