Skip to main content

This documentation is for an older version of this product. See the latest version of this content.Opens in a new tab

^%ZSTART ルーチンと ^%ZSTOP ルーチンによる開始動作と停止動作のカスタマイズ

InterSystems IRIS では、特定のイベントが発生した際に、カスタム・コードを実行できます。必要とされる手順は以下の 2 つです。

  1. ^%ZSTART ルーチン、^%ZSTOP ルーチン、またはそれらの両方を定義します。

    Note:

    ^%ZSTART^%ZSTOP は、InterSystems IRIS には含まれておらず、ユーザが作成する必要があります。

    それらのルーチンでは、特定の処理が開始または停止した際に実行するサブルーチンを定義できます。

    ^%ZSTART^%ZSTOP は、%SYS ネームスペースで作成および定義する必要がありますが、既定以外のデータベースにマッピングできます。

  2. 管理ポータルを使用して、目的のサブルーチンを呼び出すように InterSystems IRIS を構成します。

具体的には、^%ZSTART ルーチンと ^%ZSTOP ルーチンを定義し、特定の名前を持つサブルーチンを含める場合、処理の開始時または終了時に、システムによって自動的にこれらのサブルーチンが呼び出されます。サブルーチン名は以下のとおりです。

  • SYSTEM — InterSystems IRIS がシステムとして開始または停止する際に実行されます。

  • LOGIN — ユーザが %Service_Console サービスまたは Service_Telnet サービスを使用してログインまたはログアウトを実行する際に実行されます。

  • JOBJOB が開始または終了する際に実行されます。

  • CALLIN — 外部プログラムが CALLIN を開始または完了する際に実行されます。

例えば、LOGIN^%ZSTART が定義されていて、管理ポータルを使用してこのサブルーチンを有効にしている場合、ユーザがログインすると、LOGIN^%ZSTART がシステムによって自動的に呼び出されます。

これらのサブルーチンは、複雑な計算をしたり長時間実行するためのものではありません。ネットワーク・アクセスなどのように長期的に計算したり、潜在的に長時間わたって実行すると、呼び出されたルーチンが返されるまで動作の完了が遅れます。この場合、起動までに時間がかかりすぎるために、ユーザのログインに長い時間がかかるか、JOB の処理能力が低下する場合があります。

Note:

これらのサブルーチンは、通常の InterSystems IRIS 操作の一部として呼び出されます。つまり、電源障害など、InterSystems IRIS を異常終了させる外部イベントでは、^%ZSTOP への呼び出しが生成されません。

Note:

システムに ^%ZSTOP が実装され、アプリケーションに 1 つ以上の $HALT ルーチンが実装されている場合、最後の $HALTHALT コマンドで停止するまで、^%ZSTOP コードは実行されません。$HALT ルーチンが自身の HALT コマンドの発行に失敗すると、^%ZSTOP コードは実行されない可能性があります。

設計に関する考慮事項

^%ZSTART および ^%ZSTOP の実行環境には、ある程度制約があります。設計者は以下のような点に注意してください。

  • ルーチンは ObjectScript で記述しなければなりません。

  • ^%ZSTART は基本的に、引数なしの新しいコマンドで開始されるように実行されるため、ユーザのローカル変数を初期化するなどのタスクを実行するためには使用できません。

  • 任意のルーチン・エントリ・ポイントが呼び出されたときに、引数として渡される値はありません。さまざまな状況で異なるアルゴリズムが適用できる場合は、呼び出されたエントリ・ポイントはルーチンの外部、つまりグローバルやシステム変数などのデータを調査して、何を実行するかを決定する必要があります。

  • あらゆる条件下で、ルーチンがうまく動作することを確認してください。ルーチンは防御的に記述します。つまり、タスクの完了に必要なすべてのリソースがすぐ使用できる場所にあり、可能であれば演算処理が始まる前に予約されることがこれらのルーチンで確認されるようにします。発生したエラーはそのシステム関数の失敗として報告されるので、エラー抑制と処理の観点から設計を考えることが重要です。リソースが見つからない、あるいはエラーが起こる際に適切に回復できない場合、さまざまな結果がもたらされます。これには、InterSystems IRIS の開始の失敗、スタジオなどの主要な機能の動作の不具合やすぐには検知されないようなわずかな影響などが含まれます。これらのルーチンは、細心の注意を払って記述し、シミュレート条件下でデバッグし、プロダクション・システムで使用する前にシミュレート環境下でテストすることを推奨します。

  • 以前の呼び出しの間に見つかった条件や、異なるエントリ・ポイントが有効であると想定しないでください。例えば、JOB^%ZSTART への連続呼び出し間に、次の呼び出しが発生する前に前回使用したファイルが削除される可能性もあります。

  • 各エントリ・ポイントはタスクを効率的に実行します。タスクの一部が、潜在的に長時間実行するものであれば、ユーザのアプリケーションの別の部分によって後から処理するように、完了に十分な情報をキューに格納することをお勧めします。

  • 統計的に使用する目的で、エントリ・ポイントでデータを永続的に保持させる場合、データの保持にはグローバルや外部ファイルなどを使用する必要があります。

  • ルーチンを実行する環境についての条件は、最小限にしてください。例えば、このようなルーチンの開発者は、プログラムが常に特定のジョブ番号で実行されるとは予測できません。設計者は、さまざまなエントリ・ポイントが特定の順序で呼び出されることを想定できません。InterSystems IRIS を実装する複数のプロセスを呼び出す順序が、確定的であることはほとんどありません。

  • ルーチンは、システムの開始中の特定の時点で呼び出されるとは限りません。開始中のイベントの配列は、リリースのたびに、または再開のたびに変更する可能性があります。

  • いくつかの例外を除き、ルーチンでは見つけた情報をそのままにしておく必要があります。例えば、サブルーチン内で、エントリ時と終了時に $IO の値を保存してリストアせずに再代入すると、ほとんど確実にエラーの原因になります。呼び出し元のルーチンは、このような変更があったことを知る方法がありません。また、呼び出し側で実行環境に対する変更を防ぐのは非常に困難です。したがって、呼び出される側のサブルーチンで、システム処理のコンテキストを妨害しなような対策を講じる必要があります。

    この変更不可規則の一般的な例外として、アプリケーション・プログラムやインストール・プログラムに固有の、プロセス・ローカル値は変更できます。例えば、SYSTEM^%ZSTART エントリ・ポイントで、システム全体の既定値を設定します。同様に、アプリケーションのテストのために日付を設定し、月末処理の妥当性を検証することもできます。

  • ^%ZSTOP には、リモート・データベース内のグローバルへの参照を含めることができません。^%ZSTOP の呼び出し時に、これらの参照の一部がアクセスできなくなります。

  • シャットダウン・プロセス中に SYSTEM^%ZSTOP が呼び出されると、ユーザは JOB コマンドを使用して新しいプロセスを開始できなくなります。既存のプロセスを終了することはできます。

  • これらのルーチンが IRISSYS と異なるデータベースにマップされている場合、InterSystems IRIS は、IRISSYS ではなく、そのデータベースから実行しようとします。当然ながら、InterSystems IRIS は、呼び出しルーチンにそのデータベースへの適切なアクセス権限があることを事前に確認します。そのネームスペースで必要なあらゆるアプリケーション・グローバルとマッピングに対して、ルーチンに適切なアクセス権限があることを保証するのは、管理者の責任となります。

  • SYSTEM^%ZSTARTSYSTEM^%ZSTOP は、$USERNAME%SYSTEM に設定され、$ROLES%All に設定された状態で実行されます。コードを別のユーザ名で実行するには、$SYSTEM.Security.Login() を使用して目的の名前を設定してから、カスタム・コードで続行します。SYSTEM^%ZSTART コードで JOB を使用して追加プロセスを起動すると、それらのプロセスは、開始プロセスと同じユーザ名 (およびロール) を継承します。

    Caution:

    ^%ZSTART^%ZSTOP にあるすべてのエントリ・ポイントは、システム処理の重要ポイントで呼び出され、システム処理、さらにはデータ処理に対しても、広範な影響が及ぶ場合があります。これらのルーチンの指定目的により、この高いレベルの特権が必要になります。このため、これらのエントリ・ポイントで呼び出すことができるコードのすべてが、くまなくテストされていることを確認する必要があります。さらに、ユーザ指定コードが XECUTE を介して、つまり間接的に実行されることを許可しないでください。

  • 終了 (つまり停止) するプロセスでは、分散キャッシュ・クラスタ・データ・サーバからの回答を必要とする任意の参照で <FUNCTION> エラーが発生する場合があります。

Note:

アップグレードでは、InterSystems IRIS は、IRISSYS データベースにマップされた %Z* ルーチンのみを保持します。また、.INT コードまたは .MAC コードが利用できる場合、これらをリコンパイルします。他のデータベース内でのルーチンの保存は、サイト管理者が判断します。

%ZSTART および %ZSTOP を有効にする

ルーチンの設計、開発、コンパイルが完了し、テストできるようになっていれば、管理ポータルから個々のエントリ・ポイントを有効にすることができます。[システム管理][構成][追加設定][開始設定] の順に選択して [開始設定] ページに移動し、該当する個々の設定を編集します。

  • SystemStart、SystemHalt

  • ProcessStart、ProcessHalt

  • JobStart、JobHalt

  • CallinStart、CallinHalt

1 つ以上のエントリ・ポイントを無効にするには、同じプロシージャを使用しますが、値を [偽] に変更します。

^%ZSTART および ^%ZSTOP のデバッグ

最終的な環境において ^%ZSTART^%ZSTOP をデバッグする機会は制限されています。エラーが発生すると、エラーはオペレータのメッセージ・ログに書き込まれます。これは、それらのルーチンが実行している時点での現在のデバイスです。これは管理者用ディレクトリにある messages.log ファイルです。

メッセージは、失敗の原因とエラーが検出された位置を示します。この位置は、プログラム・ロジックまたはフローで実際にエラーが発生した場所とは異なる場合があります。開発者は、提供された情報からエラーの特性と場所を推定し、ルーチンを修正してください。これにより、今後のテストでは、発生するエラーの特性についてより多くの情報を得ることができるようになります。

^%ZSTART および ^%ZSTOP の削除

ルーチンを削除する前に、管理ポータル経由でエントリ・ポイントの各種オプションを必ず無効にすることを強くお勧めします。この変更を有効にするために、ポータルが InterSystems IRIS を再起動するように警告した場合は、次に進む前に再起動も実行してください。これにより、削除される間に実行されるエントリ・ポイントがなくなります。

^%ZSTART および ^%ZSTOP (および、サポートする任意のルーチン) が永続的に格納されることを覚えておいてください。これらのトレースをすべて削除するには、管理ポータルから削除してください。

以下は、システムの動作状況を追跡する単純なログの実例です。^%ZSTART^%ZSTOP の例を示します。どちらでも、3 番目の例のルーチン (^%ZSSUtil) のサブルーチンが便宜上使用されます。

^%ZSSUtil の例

このルーチンには、2 つのパブリック・エントリ・ポイントがあります。1 つは、オペレータのメッセージ・ログ・ファイルに単一行を書き込みます。もう 1 つは、ローカル・ログ・ファイルに名前と値の組み合わせのリストを書き込みます。どちらのファイルも管理者用ディレクトリにあり、そのディレクトリは、%Library.FileOpens in a new tab クラスの ManagerDirectory() メソッドにより返されます。

%ZSSUtil ;
    ; this routine packages a set of subroutines
    ; used by the %ZSTART and %ZSTOP entry points
    ;
    ; does not do anything if invoked directly
    quit

#define Empty ""
#define OprLog 1

WriteConsole(LineText) PUBLIC ;
    ; write the line to the messages log
    ; by default the file messages.log in the MGR directory
    new SaveIO

    ; save the current device and open the operator console
    ; set up error handling to cope with errors
    ; there is little to do if an error happens
    set SaveIO = $IO
    set $ZTRAP = "WriteConsoleExit"
    open $$$OprLog
    use $$$OprLog
    ; we do not need an "!" for line termination
    ; because each WRITE statement becomes its
    ; own console record (implicit end of line)
    write LineText
    ; restore the previous io device
    close $$$OprLog
    ; pick up here in case of an error
WriteConsoleExit ;
    set $ZTRAP = ""
    use SaveIO
    quit

WriteLog(rtnname, entryname, items) PUBLIC ;
    ; write entries into the log file
    ; the log is presumed to be open as
    ; the default output device
    ;
    ; rtnname: distinguishes between ZSTART & ZSTOP
    ; entryname: the name of the entry point we came from
    ; items: a $LIST of name-value pairs
    new ThisIO, ThisLog
    new i, DataString

    ; preserve the existing $IO device reference
    ; set up error handling to cope with errors
    ; there is little to do if an error happens
    set ThisIO = $IO
    set $ZTRAP = "WriteLogExit"

    ; construct the name of the file
    ; use the month and day as part of the name so that
    ; it will create a separate log file each day
    set ThisLog = "ZSS"
                _ "-"
                _ $EXTRACT($ZDATE($HOROLOG, 3), 6, 10)
                _".log"

    ; and change $IO to point to our file
    open ThisLog:"AWS":0
    use ThisLog

    ; now loop over the items writing one line per item pair
    for i = 1 : 2 : $LISTLENGTH(items)
    {
        set DataString = $LISTGET(items, i, "*MISSING*")
        if ($LISTGET(items, (i + 1), $$$Empty) '= $$$Empty)
        {
            set DataString = DataString
                           _ ": "
                           _ $LISTGET(items, (i + 1))
        }
        write $ZDATETIME($HOROLOG, 3, 1),
              ?21, rtnname,
              ?28, entryname,
              ?35, DataString, !
    }

    ; stop using the log file and switch $IO back
    ; to the value saved on entry
    close $IO
    ; pick up here in case of an error
WriteLogExit ;
    set $ZTRAP = ""
    use ThisIO
    quit

各ラベルの説明を以下に示します。

^%ZSSUtil

このルーチンは、他のルーチンと同様に、以下のコマンドから呼び出されると良好な結果が得られるように、まず QUIT コマンドを実行します。

    do ^%ZSSUtil

#DEFINE 配列は、外観をそろえるために、プログラムの本文に指定された制約を提供します。このインスタンスでは、空文字列とオペレータのメッセージ・ログのデバイス番号を指定します。

WriteConsole^%ZSSUtil

このエントリ・ポイントは非常に単純です。容量の少ない出力用に、またデバッグの出力に使用するための最小限のルーチンとして、設計されたものです。

引数として 1 つの文字列を取り、これをオペレータのメッセージ・ログに出力します。ただし、呼び出し全体にわたり、現在の $IO の接続状態を保持し、リストアするための注意が必要です。

各項目がデバイスに送信された結果、メッセージ・ログには別々のレコードが出力されます。したがって、以下のように、4 つのレコードを出力します。

    WRITE 1, 2, 3, !

最初の 3 つは 1 桁の数字から成り、4 つ目は空白行から成ります。1 行に複数の項目を記述したい場合は、呼び出し元がこれらを文字列に連結させなければなりません。

WriteLog^%ZSSUtil

このサブルーチンは、^%ZSTART または ^%ZSTOP 内の任意のエントリ・ポイントから呼び出すことができます。最初の 2 つの引数により、サブルーチンがどのように起動されたかを報告するために必要な情報を渡します。3 番目の引数は、ログに出力される名前と値の組み合わせの $LIST です。

このエントリ・ポイントは最初に、そこで使用するファイルの名前を作成します。ログ管理を簡素化するため、この名前にはルーチンが入力された月日が含まれます。したがって、このサブルーチンを呼び出すと、現地時間が深夜 12 時を経過するたびにファイルが新規作成されます。そのファイル名は呼び出し時にのみ決定されるため、引数として渡される名前と値の組み合わせはすべて、同じファイルに表示されます。

いったん名前が作成されると、$IO の現在値を後で使用できるように保存し、出力デバイスを指定されたログ・ファイルに切り替えます。OPEN コマンドに使用するパラメータによって、そのファイルがなければ作成するように指定されています。timeout がゼロの場合、InterSystems IRIS がファイルを 1 回だけ開こうとします。もし開くことができなければ失敗します。

そのファイルがいったん開かれると、コードは名前と値の組み合わせをループします。それぞれの組み合わせに対して、呼び出し元ルーチン名およびエントリ・ポイント名が書き込まれ、その行に名前と値の組み合わせが続きます(値の部分が空の文字列の場合は、名前のみが書き込まれます)。組み合わせは 1 行に 1 個ずつ出力されます。読みやすいように、各行の最初の 3 つの値は一列に並ぶようになっています。

すべての組み合わせが出力された後、ログ・ファイルを終了し、先ほど保存した $IO の値がリストアされ、コントロールは呼び出し元に返されます。

^%ZSTART

このルーチンは、実際に InterSystems IRIS に呼び出されるエントリ・ポイントを含みます。上記の ^%ZSSUtil の機能も使用します。すべてのエントリ・ポイントはほとんど同じように動作し、情報をログに配置します。SYSTEM エントリ・ポイントは、他に比べるとやや複雑で、オペレータ・メッセージ・ログにも情報を配置します。

%ZSTART ; User startup routine.

#define ME "ZSTART"
#define BgnSet "Start"
#define Empty ""

    ; cannot be invoked directly
    quit

SYSTEM ;
    ; InterSystems IRIS starting
    new EntryPoint, Items

     set EntryPoint = "SYSTEM"

     ; record the fact we got started in the messages log
     do WriteConsole^%ZSSUtil((EntryPoint
                               _ "^%"
                               _ $$$ME
                               _ " called @ "
                               _ $ZDATETIME($HOROLOG, 3)))

    ; log the data accumulate results
     set Items = $LISTBUILD($$$BgnSet, $ZDATETIME($HOROLOG, 3),
                           "Job", $JOB,
                           "Computer", ##class(%SYS.System).GetNodeName(),
                           "Version", $ZVERSION,
                           "StdIO", $PRINCIPAL,
                           "Namespace", $NAMESPACE,
                           "CurDirPath", ##class(%File).ManagerDirectory(),
                           "CurNSPath", ##class(%File).NormalizeDirectory(""),
                           "CurDevName", $System.Process.CurrentDevice(),
                           "JobType", $System.Process.JobType(),
                           "JobStatus", $ZHEX($ZJOB),
                           "StackFrames", $STACK,
                           "AvailStorage", $STORAGE,
                           "UserName", $System.Process.UserName())
    do WriteLog^%ZSSUtil($$$ME, EntryPoint, Items)

    quit
LOGIN ;
    ; a user logs into InterSystems IRIS
    new EntryPoint, Items

    set EntryPoint = "LOGIN"
     set Items = $LISTBUILD($$$BgnSet, $ZDATETIME($HOROLOG, 3))
    do WriteLog^%ZSSUtil($$$ME, EntryPoint, Items)
    quit

JOB ;
    ; JOB'd process begins
    new EntryPoint, Items

     set EntryPoint = "JOB"
     set Items = $LISTBUILD($$$BgnSet, $ZDATETIME($HOROLOG, 3))
    do WriteLog^%ZSSUtil($$$ME, EntryPoint, Items)
    quit

CALLIN ;
    ; a process enters via CALLIN interface
    new EntryPoint, Items

     set EntryPoint = "CALLIN"
     set Items = $LISTBUILD($$$BgnSet, $ZDATETIME($HOROLOG, 3))
    do WriteLog^%ZSSUtil($$$ME, EntryPoint, Items)
    quit

各ラベルの説明を以下に示します。

^%ZSTART

このルーチンはまず QUIT コマンドを実行します。エントリ・ポイントの 1 つから実行を開始するのではなく、ルーチンとして呼び出す方が良好な結果を得ることができるためです。

このルーチンも、そのルーチン自体の名前、開始文字列および空文字列に対し、指定された定数 (マクロとして) を定義します。

SYSTEM^%ZSTART

このサブルーチンは、呼び出しルーチン名、エントリ・ポイント、呼び出された日付時刻で構成された文字列を作成します。その後、WriteConsole^%ZSSUtil を呼び出してオペレータのメッセージ・ログに配置します。

その後、表示する名前と値の組み合わせのリストを作成します。これを WriteLog^%ZSSUtil に渡し、ローカル・ログ・ファイルに配置します。その後、呼び出し元に戻ります。

LOGIN^%ZSTART、JOB^%ZSTART、および CALLIN^%ZSTART

これらのサブルーチンは、オペレータのメッセージ・ログに情報を置きません。その代わり、呼び出す際に識別するための簡単な項目のリストを作成し、WriteLog^%ZSSUtil を使用して記録します。

^%ZSTOP

このルーチンは、実際に InterSystems IRIS に呼び出されるエントリ・ポイントを含み、^%ZSSUtil のサブルーチンを使用します。この例は、^%ZSTART の例と似ています。詳細は、前のセクションを参照してください。

%ZSTOP ; User shutdown routine.

#define ME "ZSTOP"
#define EndSet "End"
#define Empty ""

    ; cannot be invoked directly
    quit

SYSTEM ; InterSystems IRIS stopping
    new EntryPoint

    set EntryPoint = "SYSTEM"
    ; record termination in the messages log
    do WriteConsole^%ZSSUtil((EntryPoint
        _ "^%"
        _ $$$ME
        _ " called @ "
        _ $ZDATETIME($HOROLOG, 3)))
    ; write the standard log information
    do Logit(EntryPoint, $$$ME)
    quit

LOGIN ; a user logs out of InterSystems IRIS
    new EntryPoint

    set EntryPoint = "LOGIN"
    do Logit(EntryPoint, $$$ME)
    quit

JOB ; JOB'd process exits.
    new EntryPoint

    set EntryPoint = "JOB"
    do Logit(EntryPoint, $$$ME)
    quit

CALLIN ; process exits via CALLIN interface.
    new EntryPoint

    set EntryPoint = "CALLIN"
    do Logit(EntryPoint, $$$ME)
    quit

Logit(entrypoint, caller) PRIVATE ;
    ; common logging for exits

    new items

    set items = $LISTBUILD($$$EndSet, $ZDATETIME($HOROLOG, 3))
    do WriteLog^%ZSSUtil(caller, entrypoint, items)
    quit
FeedbackOpens in a new tab