コマンドの作成

コマンドの作成

Aceコマンドを使用するだけでなく、アプリケーションのコードベースの一部としてカスタムコマンドを作成することもできます。コマンドはcommandsディレクトリ(ルートレベル)に格納されます。次のコマンドを実行してコマンドを作成できます。

参考:makeコマンド

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 = [
'挨拶コマンドはユーザーを名前で挨拶するために使用されます',
'',
'ユーザーに花を送ることもできます。更新された住所がある場合は',
'{{ binaryName }} greet --send-flowers',
]
}

{{ binaryName }}変数の置換は、aceコマンドを実行するために使用されるバイナリへの参照です。

aliases

aliasesプロパティを使用して、コマンド名に1つ以上のエイリアスを定義できます。

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('準備中')
}
async interact() {
console.log('対話中')
}
async run() {
console.log('実行中')
}
async completed() {
console.log('完了')
}
}
メソッド 説明
prepare これはコマンドで最初に実行されるメソッドです。このメソッドでは、コマンドを実行するために必要な状態やデータを設定できます。
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ロガーを使用して表示され、コマンドのexitCode1に設定されます(非ゼロのエラーコードはコマンドが失敗したことを意味します)。

ただし、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接続を作成し、接続が失敗した場合にアプリを終了するとします。

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