記事 Hiroshi Sato · 11月 18, 2024 1m read

これは、InterSystems FAQサイトの記事です。

これは、MS-ACCESSの制限事項です。

MS-ACCESSは、インデックスが32個より多いテーブルにはリンクできません。

この問題を回避する方法として、直接テーブル(クラス)をリンクするのではなく、VIEWを使用する方法があります。

0
0 99
記事 Nobuyuki Hata · 11月 17, 2024 2m read

最近はパブリッククラウド環境でIRISを使ってアプリケーションを構築されるお客様が多数で、IRISのセキュリティ機能についてご質問を受ける機会が増えました。実際の運用で始めてセキュアなIRISを操作するよりも経験した方が良いかもと考え、その第一歩としてインストール時の初期セキュリティ設定には普段からロックダウンを指定するのはいかがでしょうか。通常セキュリティ設定の違いおよび注意点をマニュアルを参照しながらリストアップしました。

1. 初期のユーザセキュリティ設定

パスワードの最小文字数が8文字になります。またSQLのルートユーザとして作成される_SYSTEMユーザは運用開始前の無効化を推奨しているように、高いセキュリティレベルが必要な環境では不要あるいは一時的に同等の権限を付与したユーザを作成して対応可能ではないでしょうか。

2. サービスプロパティ

Use許可のPublicが不可、とはIRISにアクセスする手段を明示的に許可しないと使えないことを意図しています。予期せぬユーザーがODBCでアクセスしたり、管理コンソールを使用したりと言った事故を防ぐ有効な手段です。

また初期状態で有効化されているサービス、WebGatewayに加えてWindowsの場合Console、非WindowsではTerminalと必要最小限になっています。

0
1 97
記事 Tomohiro Iwamoto · 11月 13, 2024 7m read

以前、Azure用にOAouth2クライアントをセットアップする記事を書いた時に思ったのですが、各IdPはサンプルコードとしてPythonコードや専用のモジュールを提供しているので、それがそのまま使用できれば効率が良いのにな、と思いました。

IRISが埋め込みPython機能としてWSGIをサポートしたことにより、これが簡単に実現しそうなので、その方法をご紹介したいと思います。

導入方法

今回は、IdPとしてOKTAを使用してAuthorization Codeフローを行います。

OKTAでの設定内容

参考までに、今回使用した環境を後半に記載しています。

アプリケーションの起動

コンテナ化してありますので、コンテナのビルド環境をお持ちの方は、下記を実行してください。

git clone https://github.com/IRISMeister/iris-okta-oidc-wsgi
cd iris-okta-oidc-wsgi

python/.env.templateをpython/.envという名前でコピーを作成して、OKTAで得られる設定値を指定してください。

AUTH0_CLIENT_ID="0oaxxxxxxx"  
AUTH0_CLIENT_SECRET="qUudxxxxxxxxxxx"
AUTH0_DOMAIN="dev-xxxxx.okta.com/oauth2/default"

AUTH0_CLIENT_ID,AUTH0_CLIENT_SECRETは後述の「アプリケーション追加」で使用する画面から取得できます。 AUTH0_DOMAINは、後述の「カスタムSCOPE追加」で使用する画面から取得できる発行者URIを設定します。

docker compose build
docker compose up -d

下記でIRISの管理ポータルにアクセスできます。

http://localhost:8882/csp/sys/%25CSP.Portal.Home.zen
ユーザ名:SuperUser, パスワード:SYS

WSGI環境での実行

まずは、純粋なWSGI環境での実行を行って、設定が正しくできているかを確認します。コードはこちらを使用しました。

元々はAuth0用ですが、ほぼそのままでOKTAでも使用できました

下記のコマンドでFlaskを起動します。

docker compose exec iris python3 /usr/irissys/mgr/python/run.py

ブラウザでメインページにアクセスしてください。

http://127.0.0.1:8889/ ではリダイレクトに失敗します。

「Login」をクリックするとOKTAのログイン画面が表示されます。OKTAサインアップ時に使用した多要素認証(スマホアプリ)を使用してログインしてください。

うまく動作した場合は、取得したトークンの情報等が表示されます。namespace: USERと表示されている通り、IRISへのアクセスも行っています。

Welcome Tomohiro Iwamoto!
Logout

{
    "access_token": "eyJraWQiOi.....",
    "expires_at": 1731482958,
    "expires_in": 3600,
    "id_token": "eyJraWQ......",
    "scope": "email user/*.* profile openid",
    "token_type": "Bearer",
    "userinfo": {
        "amr": [
            "mfa",
            "otp",
            "pwd"
        ],
        "at_hash": "3cRg3plSvDPqGUwEBzefoA",
        "aud": "xxxxx",
        "auth_time": 1731477799,
        "email": "iwamoto@intersystems.com",
        "exp": 1731482958,
        "iat": 1731479358,
        "idp": "xxxxxxxxxx",
        "iss": "https://dev-xxxxxx.okta.com/oauth2/default",
        "jti": "ID.Z0icZKkP61n3WDLgD08q3QxJ4Ags6_rwhrqFX3lAUjs",
        "name": "Tomohiro Iwamoto",
        "nonce": "DYrD0GKQPyXuT6Fni1So",
        "preferred_username": "iwamoto@intersystems.com",
        "sub": "xxxxxx",
        "ver": 1
    }
}
namespace: USER

「Logout」をクリックするとOKTAからのログアウトが実行され、最初のページにリダイレクトされます。

IRIS+WSGI環境での実行

ブラウザでIRIS+WSGI用のメインページにアクセスしてください。以降の操作は同じです。

同じFlask用のコードを使用していますので、全く同じ動作になります。

何が可能になったのか

これは「IRIS+WSGIで何が可能になるか?」という問いと同じですが、本トピックに限定すると、例えばbearer tokenであるアクセストークンを、cookie(flaskのsessionの仕組み)ではなく、IRISのDB上に保存する、他のCSP/RESTアプリケーションに渡す、という応用が考えられます。

元々、CSPやIRISのRESTで作成したアプリケーションがあって、そこにIdP発行のアクセストークンを渡したい、といった用法に向いているアプローチかと思います。

また、IRISでWSGIを実行することにより、gunicornのような運用レベルのWSGI用ウェブサーバを別途立てる必要がなくなります。

OKTAでの設定内容

今回使用した環境です。

こちらのトライアル環境を使用しました。若干画面が変わっていましたが、サインアップ手順はこちらを参考にしました。登録の際にはMFA(多要素認証)としてスマホが必要です。

ログインすると、次のようなメイン画面が表示されます。

以降、アプリケーション追加、カスタムSCOPE追加、認証ポリシー設定などを行っています。

アプリケーション追加

メニューのアプリケーション->アプリケーションで、flask-code-flowという名称でアプリケーションを追加します。

「一般」タブのクライアント資格情報のは下記のようになります。

一般設定は下記のようになります。

ログイン設定は下記のようになります。複数の登録がありますが、これは実行環境に合わせて各々オリジン(ブラウザで指定するURL)が異なるためです。

ログアウト設定は下記のようになります。複数の登録がある理由はログイン設定と同じです。

「サインオン」タブの設定は下記のようになります。サインオン方法としてOpenID Connectが指定されます。

「サインオン」タブの下のほうに「ユーザー認証」というセクションがありますので、そこのポリシーの詳細リンクを押して「認証ポリシー」画面に遷移します。

「認証ポリシー」では、ルールはそのままで、アプリケーションには追加したアプリケーションを「アプリを追加」で追加登録します。

「割り当て」タブのクライアント資格情報のは下記のようになります。

カスタムSCOPE追加

リソースサーバ用にカスタムのSCOPEを追加します。「セキュリティ」->「API」でdefaultを編集して、オーディエンスとして適当なURL(ここでは http://localhost/csp/healthshare/sc/fhir/r4 )を設定します。

defaultをクリックすると下記の画面に遷移します。

「スコープ」タブを選択し、「スコープを追加」を押してカスタムSCOPEを追加します。ここではuser/*.*というスコープを追加しました。

アクセスポリシー設定

アクセスポリシーを追加します。「セキュリティ」->「API」で認可サーバ:defaultを選択します。「アクセスポリシー」タブを選択し、default policyにアプリケーションを追加します。

「ルールを追加」を押して、新しいルールを追加します。以下のような設定にしました。

0
0 68
お知らせ Mihoko Iijima · 11月 11, 2024

開発者の皆さん、こんにちは!

2回目の開催となったミートアップですが、11月8日(金)に無事、開催を終えることができました。ご参加いただきましたメンバーの皆様、ありがとうございました!

今年のミートアップでは、ワークショップを開催してみました。13時半~17時半の約4時間(!)もの間、ご持参いただいたパソコンでもくもくと進めていただいていたように思えます。

ミートアップのワークショップで使用した内容は、全て以下リポジトリに公開しております。

👉https://github.com/Intersystems-jp/meetup2024WorkShop

以下、写真を添えながら当日の様子を少しご紹介します。

第1部は、ワークショップを合計5種類用意いたしました。

Python入門」、「Embedded PythonでIRISデータにアクセスしよう」までは、全員一緒のタイミングで説明を聞いていただきながら、内容を確認するワークショップを行いました。

10分間の休憩を挟んだ後は、ご用意しました3種のワークショップ:「WSGI-Flask」「NiceGUI+SQL Alchemyを使ってアプリケーションをつくってみよう」「機械学習で手書き数字の識別に挑戦」のなかから好きな内容にチャレンジいただきました。

0
0 179
お知らせ Rie Tokue · 11月 11, 2024

 

ご好評いただいておりますインターシステムズ開発者向けウェビナー、今年最後の回は以下の通り開催いたします。

お忙しい時期ではありますが、皆様のご参加をお待ち申し上げております。

テーマ:「IRISで実現する極小オーバヘッドの IoTエッジサーバー」

日時:2024年12月10日(火)13時30分~14時

ご登録はこちらから

【概要】

IoTデバイスで発生するデータをサーバに送信して、アラートを管理する、後の利活用のためにデータベースに保存する、といったシナリオは多くの分野で見受けられます。その際、伝送するデータのフォーマットは、様々な処理系で利用可能で、データサイズが小さく、スキーマ定義が容易であることが望ましいです。

データフォーマットは、全体のパフォーマンスに影響を与える多数ある要素のひとつにすぎませんが、最もソフトウェアが貢献できる要素でもあります。本セミナでは、通信プロトコルとしてMQTT, メッセージフォーマットとしてApache Avro、DBとしてIRIS、コードとして(埋め込み)Pythonを使用した実行環境を「シンプルな構成」で実現する例をご紹介します。

0
0 77
お知らせ Toshihiko Minamoto · 11月 6, 2024

VS Code には強力なスニペット機能が備わっており、Marketplace は開発者がスニペットを公開して使用できる方法を提供しています。 ただし、Marketplace での公開は面倒である上、InterSystems コーダーを対象としたスニペットは、現実的には Marketplace の訪問者のごく少数にしか興味を持たれません。

このことから、oex-vscode-snippets-template を作成する発想を得ました。InterSystems 開発者向けのコードスニペットを公開するための専用リポジトリを作成する GitHub テンプレートです。

また、oex-vscode-snippets-example というスニペットサンプルのリポジトリも Open Exchange で公開され、IPM / ZPM を使ってインストールされます。 以下のようにして、ネームスペースにパッケージをインストールします。

zpm "install vscode-snippets-John.Murray-example"

次に Server Manager と InterSystems ObjectScript 拡張機能を使用してそのネームスペースのサーバーサイドを編集する際は、コード補完(Ctrl+Space)リストに TODO コメントを挿入するための複数のスニペットが含まれるようになります。

oex-vscode-snippets-template は 2023 Grand Prix に出品中です。 気に入っていただけたら投票してください。 フィードバックもお待ちしています。

0
0 44
お知らせ Ayumu Tanaka · 9月 16, 2024

※ 本内容は随時更新予定です。ワークショップに必要な内容をご覧いただき、参加のご検討などしていただければ幸いです。
Pythonワークショップにご参加いただく場合は、事前に以下の環境をご用意ください。

  • IRIS 2024.1.1 for Windows Community Edition (※ これからダウンロードされる方は、バージョンが異なりますので下記コメントをご確認ください)
    • キットダウンロードはこちらの記事をご覧ください。
    • インストールオプションはデフォルト (インストールタイプ: 開発、初期セキュリティ設定: 最小)
  • Visual Studio Code (任意のバージョン) と ObjectScript用エクステンション
    • エクステンションのインストール方法はこちらの記事をご覧ください。
  • 以下のPythonライブラリを irispip (<IRISインストールディレクトリ\bin\irispip.exe) でインストール
    • flask, nicegui, sqlalchemy-iris,  scikit-learn,  numpy, pandas
8
0 323
記事 Hiroshi Sato · 10月 7, 2021 3m read

これは InterSystems FAQ サイトの記事です。
ジャーナルファイルのサイズが大きすぎて、管理ポータルで検索やフィルタリング等できない場合、以下の2つの方法で参照することができます。

① ^JRNDUMP ユーティリティを使用する方法
② プログラムで参照する方法

============================================================ 

① ^JRNDUMP ユーティリティを使用する方法 例えば、グローバル参照 ^ABC を含むジャーナルファイルのすべてのレコードを選択する場合は、以下のようになります。


※以下、すべてのコマンドは %SYS ネームスペースで実行してください。

DO SELECT^JRNDUMP("C:\MyCache\mgr\journal\YYYYMMDD.001","","","^ABC",1)

 

グローバル参照 ^ABC に完全に一致するレコードのみを選択する場合は、以下のようになります。 

DO SELECT^JRNDUMP("C:\MyCache\mgr\journal\YYYYMMDD.001","","","^ABC",0)

 

グローバル ^ABC に対するローカルの Set 処理のレコードのみを選択する場合は、以下のようになります。 

4
0 504
記事 Toshihiko Minamoto · 11月 5, 2024 1m read

Studio で最も便利な機能の 1 つにコードスニペットがあります。

以下は、スニペットを VSCode に追加する方法です。

以下は、一般的な手順です。

1. ファイル - 設定 - ユーザースニペットに移動し、objectscript を選択します。

2. スニペットを追加します。以下に例を示します。

"SQL Statement": {
    "prefix": ["sql"],
    "body": ["#dim rs As %SQL.ISelectResult",
            "set rs = ##class(%SQL.Statement).%ExecDirect(,\"SELECT * FROM\")",
            "while rs.%Next() {",
            "\twrite rs.ID, !",
            "}"]
}

要素は以下のように定義されています。

  • prefix - スニペットを表示するのに入力する必要のある文字
  • body - スニペットの本体

さらにスニペットには、以下のようにプレースホルダーも含められます。

"Method": {
    "prefix": ["method"],
    "body": ["set sc = ##class(${1:class}).${2:method}()"]
}

このスニペットを挿入すると、最初のプレースホルダーの開始点に自動的に移動します。プレースホルダーは <TAB> でスクロールできます。

コーディングをお楽しみください!

0
0 116
お知らせ Mihoko Iijima · 10月 28, 2024

開発者の皆さん、こんにちは!

第2回 技術文書ライティングコンテスト に応募された作品のボーナスポイント獲得状況をお知らせします📣(順位発表は11月1日を予定しています)

記事 EmbeddedPythonに関連する記事(4点) 生成AIに関連する記事(4点) FHIRに関連する記事(3点) コードの記述が含まれる記事(2点) 動作するコードサンプルをGitリポジトリへ公開する(5点) 記事の内容に関連した画面キャプチャや図を貼る(1点) 合計点
FHIR Object Modelを使ったInteroperability開発     11
UnitTest(ユニットテスト)の自動化について考察        

6

IRIS環境設定の自動化について~インストールマニフェストの利用~     12
Embedded Python を利用する時の注意点

      7
IRIS開発における生成AIの活用について       7
SourceControlを用いた自動ソースチェックツールについて       8
0
0 71
お知らせ Mihoko Iijima · 9月 4, 2024

コミュニティの皆さん、こんにちは!

開発者コミュニティ AI 懸賞企画 お楽しみいただけましたか? まだまだ改良の必要がありそうですが、DC AIを利用して何か新しい回答が得られていることを願っています。

この投稿では、優勝者を発表します!🎊(抽選の様子を動画でご紹介しています。ぜひご覧ください!)

4
0 93
記事 Tomoko Furuzono · 10月 27, 2024 1m read

これは、InterSystems FAQサイトの記事です。


InterSystemsでは、以前は、OSの特定リリースに対して製品の検証は実施しておりませんでしたが、
バージョン2022.1以降においては、OSのマイナーバージョンに対する検証を実施しております。
 

最新のサポートプラットフォームの情報については、下記の記事をご確認ください。
※2024年12月現在の最新情報
InterSystems サポートプラットフォーム最新情報 Q4-2024

★最新情報は開発者コミュニティにて随時発信いたしますので、以降の状況については、上記記事の継続記事をご確認ください。

(ご参考)
以前の状況についてはこちら
Windowsのサービスパックの適用に対する製品サポートについて
Windows Serverのリリースの違いは、サポートバージョンに影響しますか?

0
0 41
記事 Tomoko Furuzono · 10月 27, 2024 1m read

これは、InterSystems FAQサイトの記事です。

インターシステムズは、特定のオペレーティングシステムのパッチやサービスパックに対して、製品の検証は実施しておりません。

これらの保証については、オペレーティングシステムベンダーが互換性を保証する限りにおいて、提供されます。
まれなケースで、インターシステムズの製品を稼動するために、特定のパッチやサービスパックを必要とするケースもあります。
その様な特別な状況の詳細は、サポートサーバプラットフォームに明記しています。以下ドキュメントをご参照ください。

サポートサーバプラットフォームについて

明記されていない場合には、オペレーティングシステムベンダーが互換性を保証する限りにおいて、パッチやサービスパックもサポート対象となります。

※2022.1以降のバージョンにおいては、OSのマイナーバージョンにおいても検証を実施しております。

0
0 62
InterSystems公式 Masahito Miura · 10月 24, 2024 2m read

InterSystems IRIS、IRIS for Health、HealthShare HealthConnect のメンテナンスリリース 2023.1.5 と 2024.1.2 がリリースされました
 

InterSystems IRISInterSystems IRIS for HealthHealthShare Health Connect の2つのメンテナンスリリースがリリースされました。
✅ 2023.1.5

リリース 2023.1.5 は、以前のリリース 2023.1.x のバグフィックスを提供します。

詳細な変更リストとアップグレード・チェックリストは、以下のページにあります :

✅ 2024.1.2
リリース 2024.1.2 は、以前のリリース 2024.1.x のバグフィックスを提供します。

詳細な変更リストとアップグレード・チェックリストは、以下のページにあります :

0
0 52
記事 Toshihiko Minamoto · 10月 24, 2024 8m read

CI/CD シリーズの新しい章へようこそ。ここでは、InterSystems テクノロジーと GitLab を使用したソフトウェア開発の様々な可能なアプローチを取り上げています。 今回も相互運用性について説明を続けますが、特に相互運用性デプロイの監視に焦点を当てます。 まだアラートをすべての相互運用性プロダクションにセットアップしていない場合は、それをセットアップしてエラーとプロダクションの状態についての一般的なアラートを取得できるようにしてください。

非活動タイムアウトは、すべての相互運用性ビジネスホストに共通する設定です。 ビジネスホストは、「Inactivity Timeout(非活動タイムアウト)」フィールドに指定された秒数以内にメッセージを受信しない場合に非アクティブステータスになります。 プロダクションの監視サービスはプロダクション内のビジネスサービスとビジネスオペレーションのステータスを定期的に確認し、非活動タイムアウト期間内にアクティビティがない場合にその項目を「非アクティブ」にマークします。 デフォルト値は 0(ゼロ)です。 この設定が 0 である場合、ビジネスホストはアイドル状態がどれほど続いても Inactive にマークされることはありません。

これはアラートを生成し、構成されたアラートと合わせてプロダクションの問題に関するリアルタイム通知を可能にするため、非常に便利な設定です。 ビジネスホストがアイドル状態である場合、プロダクション、統合、またはネットワーク接続に調べる価値のある問題がある可能性があります。 ただし、ビジネスホストには一定時間の非活動タイムアウトを 1 つしか設定できないため、夜間、週末、休日などのトラフィックの少ない既知の期間中に不要なアラートを生成する可能性があります。 この記事では、動的な非活動タイムアウトを実装するためのいくつかのアプローチを説明します。 機能する例(現在ある顧客サイトの本番環境で実行しているもの)を紹介していはいますが、この記事は独自の動的な非活動タイムアウトの実装を構築するためのガイドラインを紹介することを目的としているため、ここに提案するソリューションを唯一の代替手法と見なさないようにしてください。

構想

相互運用性エンジンは、各ビジネスホストをサブスクリプトとして、最新のアクティビティのタイムスタンプを値として含む特殊な HostMonitor グローバルを維持しています。 非活動タイムアウトを使用する代わりに、このグローバルを監視し、HostMonitor の状態に基づいてアラートを生成することにします。 HostMonitor は、非活動タイムアウト値が設定されているかに関係なく維持されます。常にオンの状態です。

実装

まず初めに、以下のようにして HostMonitor グローバルを反復処理します。

Set tHost=""
For { 
  Set tHost=$$$OrderHostMonitor(tHost) 
  Quit:""=tHost
  Set lastActivity = $$$GetHostMonitor(tHost,$$$eMonitorLastActivity)
}

監視サービスを作成するには、各ビジネスホストに対して以下のチェックを実行する必要があります。

  1. ビジネスホストが完全に動的非活動タイムアウトのスコープで管理されるかを決定します(たとえば、トラフィックの多い hl7 インターフェースには通常の非活動タイムアウトを適用できます)。
  2. ビジネスホストがスコープ内である場合、最後のアクティビティからの時間を計算する必要があります。
  3. 次に、非活動時間といくつかの条件(日中/夜間、曜日)に基づいて、アラートを送信するかを決定する必要があります。
  4. アラートレコードを送信する場合は、アラートを 2 回送信しないように、最後のアクティビティの時間を記録する必要があります。

すると、コードは以下のようになります。

Set tHost=""
For { 
  Set tHost=$$$OrderHostMonitor(tHost) 
  Quit:""=tHost
  Continue:'..InScope(tHost)
  Set lastActivity = $$$GetHostMonitor(tHost,$$$eMonitorLastActivity)
  Set tDiff = $$$timeDiff($$$timeUTC, lastActivity)
  Set tTimeout = ..GetTimeout(tDayTimeout)
  If (tDiff > tTimeout) && ((lastActivityReported="") || ($system.SQL.DATEDIFF("s",lastActivityReported,lastActivity)>0)) {
    Set tText = $$$FormatText("InactivityTimeoutAlert: Inactivity timeout of '%1' seconds exceeded for host '%2'", +$fn(tDiff,,0), tHost)
    Do ..SendAlert(##class(Ens.AlertRequest).%New($LB(tHost, tText)))
    Set $$$EnsJobLocal("LastActivity", tHost) = lastActivity
  } 
}

カスタムロジックを実際に格納している InScopeGetTimeout メソッドを実装したら、完了です。 この例では、日中のタイムアウト(Day Timeout、これはビジネスホストごとに異なる可能性がありますが、デフォルト値があります)と夜間のタイムアウト(Night Timeout、追跡されているすべてのビジネスホストに共通)があるため、ユーザーは以下の設定を指定する必要があります。

  • スコープ: ビジネスホスト名(または名前の一部)とそれぞれのカスタムの DayTimeout 値を組み合わせた、行あたり 1 つのリスト。 スコープ内のビジネスホストのみが追跡されます(少なくとも 1 つのスコープに対して $find(host, scope) 条件を満たす必要があります)。 すべてのビジネスホストを監視する場合は空白のままにします。 例: OperationA=120
  • DayStart: 00:00:00 からの秒。日中はこの後に開始します。 DayEnd より少ない数値である必要があります。 すなわち、 06:00:00 AM は 6*3600 = 21600 となります。
  • DayEnd: 00:00:00 からの秒。日中はこの後に終了します。 DayStart より大きな数値である必要があります。 すなわち、 08:00:00 PM は (12+8)*3600 = 72000 となります。
  • DayTimeout: 日中にアラートを発生させるための秒単位のデフォルトのタイムアウト値。
  • NightTimeout: 夜間にアラートを発生させるための秒単位のタイムアウト値。
  • WeekendDays: 週末と見なされる曜日。 カンマ区切りです。 週末の場合、NightTimeout が 1 日 24 時間適用されます。 例: 1,7。日付の DayOfWeek 値は、$SYSTEM.SQL.Functions.DAYOFWEEK(date-expression) を実行してチェックします。 デフォルトでは、返される値は以下の曜日を表します: 1 — 日曜日、2 — 月曜日、3 — 火曜日、4 — 水曜日、5 — 木曜日、6 — 金曜日、7 — 土曜日。

完全なコードを確認できますか、特に興味深い点はないと思います。 単に InScope と GetTimeout メソッドを実装しているだけです。 他の基準を使用して、InScope と GetTimeout メソッドを必要に応じて調整できます。

問題

言及する問題は 2 つあります。

  • 非アクティブビジネスホストには黄色いアイコンがない(ホストの非活動タイムアウト設定値がゼロであるため)。
  • Out-of-host 設定 - 開発者は新しいビジネスホストを追加するたびにこのカスタム監視サービスを更新して、動的な非活動タイムアウトを使用することを覚えておく必要があります。

代替手法

上記のソリューションを実装する前に、以下のアプローチを探りました。

  1. 日中/夜間が開始するときに InactivityTimeout 設定を変更するビジネスサービスを作成する。 当初、この方法で進もうと考えましたが、主に、InactivityTimeout 設定を変更するたびに影響のあるすべてのビジネスホストを再起動しなければならないなど、多数の問題に遭遇しました。
  2. カスタムアラートプロセッサーに、夜間の InactivityTimeout である場合にアラートを送信する代わりにアラートを抑止するというツールを追加する。 Ens.MonitorServoce からの非活動アラートが LastActivity を更新するため、カスタムアラートプロセッサーからは「実際の」最終アクティビティタイムスタンプを取得する方法がわかりません(Ens.MessageHeader をクエリする以外で)。 また「夜間」である場合、ホストの状態を OK に戻し、まだ夜間の InactivityTimeout でなければアラートを抑止します。
  3. Ens.MonitorService を拡張する。これは、OnMonitor コールバック以外は可能に思えませんでしたが、他の目的には役立ちます。

まとめ

必ずアラートをすべての相互運用性プロダクションにセットアップして、エラーやプロダクションの状態についての一般的なアラートを取得します。 静的な非活動タイムアウトで十分でなければ、動的な実装を簡単に作成できます。

リンク

0
0 53
お知らせ Mihoko Iijima · 10月 20, 2024

開発者の皆さん、こんにちは!

11月8日(金)は開発者コミュニティのミートアップ開催日です。申し込みはお済でしょうか??

昨年、大阪で初回ミートアップを開催した際、コミュニティメンバー同士での交流をとても楽しみにしてくださる方が多かった印象を受けました。

そこで、今年はメンバー同士の結束をより高められたら・・と思い、ミートアップ2024Tシャツを作成しました!

 

0
0 92
お知らせ Mihoko Iijima · 10月 20, 2024

開発者の皆さん、こんにちは!

🖋 InterSystems Japan 技術文書ライティングコンテスト2024:IRISに関連した記事 🖋の応募受付期間が終了し、残るは投票のみとなりました!

第2回目のコンテストは✨6作品✨の応募がありました!

コミュニティメンバーは「イイネ」 をクリックすることで投票できます。2024年10月31日(木)23時59分59秒 まで投票受付中です。

素晴らしい6作品のなかから、🔥これだ!🔥と思う記事の「イイネ」をクリックしてください。

以下、投票方法についてご案内します。

(1) 開発者コミュニティにログインする。

ログインアカウントをお持ちでない方は、コミュニティページ上部の  (下図赤枠)をクリックし、アカウント登録を行って下さい。

クリックした後の流れは「アカウント作成方法」の記事をご参照ください。

(2) 投稿記事一覧ページに移動します。

投稿記事を👀じっくり読みます👀

(3) 「いいね」をクリックします。

投稿記事一覧ページ上でクリックする場合はそれぞれの投稿画面左下にあるのマークをクリックします。クリック前はグレーの表示ですがクリック後に変わります。

各記事を参照している状態で「いいね」をクリックする場合は、画面左側にアイコン一覧が縦に並んでいますのでのマークをクリックします。

良い記事が見つかったらをクリックして作者を応援しましょう!📣

0
0 89
お知らせ Mihoko Iijima · 8月 2, 2024

開発者の皆さん、こんにちは!

昨年初めて開催した日本の InterSystems 開発者コミュニティのコンテストですが、📣今年も開催します!📣

テーマは昨年と同じで InterSystems IRIS/InterSystems IRIS for Health に関連した内容であればどのような内容でもご応募いただけます。

🖋 InterSystems Japan 技術文書ライティングコンテスト2024:IRISに関連した記事 🖋

🎁 参加賞:投稿いただいた方全員に👚開発者コミュニティ特製Tシャツ👕をプレゼントいたします!

🏆 特別賞:選ばれた3作品に特別賞があります。

8/30更新:賞品情報追加しました!ぜひご確認ください!👇

4
0 324
記事 Kawasaki Kazuhito · 10月 14, 2024 15m read

開発者の皆様はじめまして。 私からはIRISのソースコントロール機能を用いたソースの自動チェック機能のご紹介をしたいと思います。 チーム開発では、ソースの可読性や実装方法等がある程度統一されるようにコーディング規約を作成すると思います。 しかし、メンバーの入れ替わりでコーディング規約の説明をしていても徹底されないことが起こることも少なくありません。 なので、ソースコントロールを使用してコンパイル時に自動的にチェックするようにしました。 IRIS内で完結させるメリットとして、エラーチェックだけでなくチェック後にエラーがなければコンパイルまで自動で行えること、 %Dictionary.ClassDefinition(クラス定義)を使用できるので、チェッククラスを作成しやすいこと等があげられます。

目次

  1. ソースコントロールについて
  2. 今回用意したチェック用クラスの紹介
  3. ソースコントロールへの設定
  4. 実際の動作
  5. 感想

1.ソースコントロールについて まず、ソースコントロールについて簡単に記載します。 ソースコントロールとは、一般的にコードに対する変更を追跡し管理することを表します。 IRISのソースコントロール機能には様々なメソッドが用意されています。 今回はそれを使用することでソースの自動チェック機能を実現していきます。 参考リンク:InterSystems IRIS とソース・コントロール・システムの統合、 ソース・コントロール設定の構成

2.今回用意したチェック用クラスの紹介 今回作成したチェック用クラスには基底クラスとして、「%Studio.SourceControl.Base」と「%Studio.Extension.Base」(%Studio.SourceControl.Baseの基底クラス)を使用しています。 上記のクラスにはログイン時のイベントやロード前イベントなどが定義されており、今回は「OnBeforeCompile」(コンパイル前イベント)を使用しました。 image

では、実際のチェック用クラスの内容をご紹介します。 今回は以下をコーディング規則として実装をしています。 ①クラスの命名チェック - 「XXXX」始まりのクラス名であること ②インデントチェック - インデントは4の倍数の半角空白で埋めること ③変数の利用チェック - 定義した変数は利用すること ④引数の利用チェック - パラメータとして受け取った引数は利用すること

Class User.CompileChk Extends %Studio.SourceControl.Base
{

///  処理概要 :コンパイル前チェック
///  <br>IN :InternalName : コンパイル対象クラス
///  <br>OUT :%Status
///  <br>処理詳細:規約に則さない実装がされている場合、コンパイルエラーにする。
Method OnBeforeCompile(InternalName As %String, ByRef qstruct As %String) As %Status
{
    Set InternalName = $REPLACE(InternalName, ".CLS", "")
    Set clsDef = ##Class(%Dictionary.ClassDefinition).%OpenId(InternalName)

    Set SKIPuFLG = $$$NO
    Write !,"****************コンパイルチェック開始****************",!
    Write "TARGET : "_InternalName,!
    Set hasErr = 0
    
    #; クラス名チェック
    Set hasErr = hasErr + '##class(User.Chk.ClassNamingChecker).%New().IsCorrectDefine(clsDef)
    #; インデントチェック
    Set hasErr = hasErr + '##class(User.Chk.IndentChecker).%New().UseWrongIndent(clsDef)
    #; 変数の利用チェック
    Set hasErr = hasErr + '##class(User.Chk.UseValChecker).%New().UseVal(clsDef)
    #; 引数の利用チェック
    Set hasErr = hasErr + '##class(User.Chk.UseArgsChecker).%New().UseArgs(clsDef)
    

    Write "****************コンパイルチェック完了****************",!
    If (hasErr > 0) {
        Return $$$ERROR($$$GeneralError, "コンパイルエラーがあります。")
    } Else {
        Return $$$OK
    }
}

}

①クラスの命名チェッククラス - User.Chk.ClassNamingChecker Class User.Chk.ClassNamingChecker Extends %RegisteredObject {

///  処理概要 :クラス定義の命名規約違反チェック
///  <br>IN :clsDef : クラス定義
///  <br>OUT :%Boolean
///  <br>処理詳細:クラスの命名がコーディング規約に従っているかどうかをチェックする。
Method IsCorrectDefine(clsDef As %Dictionary.ClassDefinition) As %Boolean
{
    Write "*クラス名チェック",!

    Set ret = $$$YES
    If (clsDef '= "") {
        Set clsName = clsDef.Name
        Set ret = ..WriteStartWithStrErr(clsName)
    }

    Return ret
}

///  処理概要 :命名先頭不正のエラー表示
///  <br>IN :clsName クラス名/ keyword キーワード
///  <br>OUT :%Boolean
///  <br>処理詳細:クラス名の先頭がキーワードで開始していなければエラーを表示する。
Method WriteStartWithStrErr(clsName As %String) As %Boolean [ Private ]
{
    If ($FIND(clsName, ".XXXX") > 0) {
        #; OK
        Return $$$YES
    } Else {
        Write "E: クラス名はXXXXという単語で始まる必要があります。",!
        Return $$$NO
    }
}

}

クラス内で行っていること 引数として%Dictionary.ClassDefinition(クラス定義)を受け取り、クラス定義内のプロパティであるNameを使用することで クラス名を取得。取得したクラス名に対して、「.XXXX」を$FINDで検索することでクラスの先頭が「XXXX」であるかチェックを行います。

②インデントチェック - User.Chk.IndentChecker

Class User.Chk.IndentChecker Extends %RegisteredObject
{

///  処理概要 :インデント不正チェック
///  <br>IN :clsDef : クラス定義
///  <br>OUT :%Boolean
///  <br>処理詳細:インデントが4の倍数になっているかをチェックをする。
Method UseWrongIndent(clsDef As %Dictionary.ClassDefinition) As %Boolean
{
    Write "*インデント不正チェック",!
    Set isCorrect = $$$YES
    Set count = clsDef.Methods.Count()
    For i = 1: 1: count {
        Set cnt = 0
        Set method = clsDef.Methods.GetAt(i)
        Do method.Implementation.Rewind()

        While ('method.Implementation.AtEnd) {
            Set cnt = cnt + 1
            Set line = method.Implementation.ReadLine()
            If (line = "") {
                Continue
            }

            If ('$MATCH(line, "^( {4}){1,}[^ ].*")) {
                Set isCorrect = $$$NO
                Write "E: インデントが4の倍数になっていません。: "_method.Name_"+"_cnt_line,!
            }
        }
    }

    Return isCorrect
}

}

クラス内で行っていること 引数として%Dictionary.ClassDefinition(クラス定義)を受け取り、クラス定義内のプロパティであるMethods.Count()でメソッドの数を取得。 メソッドごとに1行ずつチェックを行います。チェックは正規表現を使用(^( {4}){1,}[^ ].*の部分)し、半角スペースが4の倍数になっているかチェックを行います。

③変数の利用チェック - User.Chk.UseValChecker

Class User.Chk.UseValChecker Extends %RegisteredObject
{

///  処理概要 :変数の利用チェック
///  <br>IN :clsDef : クラス定義
///  <br>OUT :%Boolean
///  <br>処理詳細:定義された変数が利用されているかをチェックをする。
Method UseVal(clsDef As %Dictionary.ClassDefinition) As %Boolean
{

    Set isCorrect = $$$YES
    Set count = clsDef.Methods.Count()
    For i = 1: 1: count {
        Set cnt = 0
        Set method = clsDef.Methods.GetAt(i)
        Do method.Implementation.Rewind()

        Set args = method.FormalSpec
        Set argList = {}
        For j = 1: 1: $LENGTH(args, ",") {
            Set arg = $REPLACE($REPLACE($REPLACE($PIECE($PIECE(args, ",", j), ":", 1), "&", ""), "*", ""), "...", "")
            If (arg = "") {
                Continue
            }
            Do argList.%Set(arg, "")
        }

        Set valList = {}
        While ('method.Implementation.AtEnd) {
            Set cnt = cnt + 1
            Set line = method.Implementation.ReadLine()
            If (line = "") {
                Continue
            }
            If (..HasComment(line)) {
                Continue
            }

            If ($FIND(line, "Set ") > 0) {
                Set valNm = $PIECE($REPLACE($PIECE($PIECE(line, "Set ", 2), "="), " ", ""), "(")
                #; オブジェクトへの参照は対象外。
                If (($FIND(valNm, ".") = 0) && ($FIND(valNm, "$") = 0)) {
                    #; 変数の定義があればObjectに登録。
                    If (('valList.%IsDefined(valNm)) && 'argList.%IsDefined(valNm)) {
                        Do valList.%Set(valNm, $$$NO)
                    }
                }
            }

            Set iter = valList.%GetIterator()
            While iter.%GetNext(.key, .value) {
                If ($FIND($REPLACE(line, "Set "_key_" ", ""), key) > 0) {
                    Do valList.%Set(key, $$$YES)
                }
            }
        }
        Set iter = valList.%GetIterator()
        While iter.%GetNext(.key, .value) {
            If ('value) {
                Write "E: "_method.Name_"() にて変数"_key_"は定義されていますが、利用されていない可能性があります。",!
                Set isCorrect = $$$NO
            }
        }
    }
    Return isCorrect
}

Method HasComment(line As %String) As %Boolean [ Private ]
{
    Return ($MATCH(line, "^( )*#;.*") > 0) || ($MATCH(line, "^( )*//.*") > 0)
}

}

クラス内で行っていること ②で行ったようにメソッド単位でチェックを行います。method.FormalSpec でメソッドの引数のリストを含む文字列を取得します。 上記で取得した文字列から、引数のみを抽出して引数リストを作ります。ここまで来たら、メソッドを1行ずつチェックしていきます。 HasCommentメソッドでコメントの場合は読み飛ばすようにしています。まず、「Set」の使用をチェックします。(If ($FIND(line, "Set ") > 0) {) 使用されている場合でもオブジェクトへの参照は対象外とするため、「.」や「$」が使用されている場合は読み飛ばします。(If (($FIND(valNm, ".") = 0) && ($FIND(valNm, "$") = 0)) {) 「.」や「$」が使用されていないかつ、引数のリストに存在しない場合は後のチェックのためにリストに追加します。(value側は$$$NOで登録しておきます) チェックリストを順番にリストのキー項目が定義箇所以外で使用されているかチェックしていきます。(L50~L54) 使用されている場合、該当キー項目のvalueを$$$YESに更新しておきます。 チェック処理としては上記で完了です。あとはvalueが$$$NOの項目を洗い出して、チェック完了となります。

④引数の利用チェック - User.Chk.UseArgsChecker

Class User.Chk.UseArgsChecker Extends %RegisteredObject
{

///  処理概要 :引数の利用チェック
///  <br>IN :clsDef : クラス定義
///  <br>OUT :%Boolean
///  <br>処理詳細:引数が利用されているかをチェックする。
Method UseArgs(clsDef As %Dictionary.ClassDefinition) As %Boolean
{
    Write "*引数の利用チェック",!
    Set ngKeyword = $LISTBUILD(")", """", "}")

    Set isCorrect = $$$YES
    Set count = clsDef.Methods.Count()
    For i = 1: 1: count {
        Set method = clsDef.Methods.GetAt(i)
        Set args = method.FormalSpec

        Do method.Implementation.Rewind()
        Set str = method.Implementation.Read()
        For j = 1: 1: $LENGTH(args, ",") {
            Set arg = $REPLACE($REPLACE($REPLACE($PIECE($PIECE(args, ",", j), ":", 1), "&", ""), "*", ""), "...", "")
            If (arg = "") {
                Continue
            }

            Set isIgnore = $$$NO
            Set ptr = 0
            While $LISTNEXT(ngKeyword, ptr, value) {
                #; NGリストの内容が含まれていると、切り出し対象外。
                If ($FIND(arg, value) > 0) {
                    Set isIgnore = $$$YES
                    Quit
                }
            }
            If (isIgnore) {
                Continue
            }

            If ($FIND(str, arg) = 0) {
                Write "E: 引数が利用されていません。: "_method.Name_"/"_arg,!
                Set isCorrect = $$$NO
            }
        }
    }

    Return isCorrect
}

}

クラス内で行っていること まず、コメントなどを引っ掛けないためにチェックしない文字を定義します。(L10) ③と同様にメソッド単位でチェックをするようにします。(L13~) メソッドの引数を取得します。(L16) メソッドの最初の行からチェックするようにポインタをストリームの先頭にしてメソッドの読込を行います。(L18、L19) 引数の数分チェックをまわしていきます。(L20) 引数の中にチェックしない文字が入っているかチェックします。(L28~L34) チェックしない文字が入っていない場合は、読み込んだメソッドの中で引数が使用されているかチェックを行います。(L39~L42)

3.ソースコントロールへの設定 管理ポータルにて、[システム管理]⇒[構成]⇒[追加の設定]⇒[ソースコントロール] を開くと ソースコントロールの設定画面となります。 imageimage

ソースコントロールクラス名の一覧には「%Studio.SourceControl.Base」クラスを継承したクラスが表示されます。 ソースコントロールを行いたいネームスペースを選択し、使用したいソースコントロールクラスを選択⇒保存します。 今回はUSERのネームスペースにチェック用クラス用意していますが、%SYSにソースコントロールクラスを作成することで全てのネームスペースに対して使用することができます。

4.実際の動作 今回テスト用に用意したクラスが以下のクラスです。

Class User.Test.NewClass1 Extends %RegisteredObject
{

///  処理概要 :テストメソッド
///  <br>IN :Str1 : テスト用文字列1
///  <br>IN :Str2 : テスト用文字列2
///  <br>OUT :%Boolean
Method TestMethod(Str1 As %String, Str2 As %String) As %Boolean
{
   Set test1 = Str1
    Set test2 = "TEST"
    
    Set ^TESTG(test1,"abc") = "hugehuge"
    
    Return $$$OK
}

}

クラス名が「XXXX」始まりでないこと。 - クラスの命名チェック インデントが4の倍数個の半角スペースになっていないこと。(L10) - インデントチェック 定義した変数test2が使用されていないこと。 - 変数の使用チェック TestMethodの引数として用意したStr2が使用されていないこと。 - 引数の使用チェック

実際にコンパイルした結果がこちらです。 image

すべてチェックに引っかかっており、コンパイルもされないようになっています。 では、チェッククラスに指摘された部分を修正したものをコンパイルしてみます。

Class User.Test.XXXXNewClass1 Extends %RegisteredObject
{

///  処理概要 :テストメソッド
///  <br>IN :Str1 : テスト用文字列1
///  <br>IN :Str2 : テスト用文字列2
///  <br>OUT :%Boolean
Method TestMethod(Str1 As %String, Str2 As %String) As %Boolean
{
    Set test1 = Str1
    Set test2 = "TEST"
    Set ^TESTG(test1,test2) = Str2
    Return $$$OK
}

}

image

見事にコンパイルが成功しました。

5.感想 今回参考例として4つのチェックを行いましたが、工夫や組み込み方次第では色々なチェックを組み込めると感じました。 Ex.) 変数がキャメルケースになっているか、利用してほしくないプロパティ等が使用されているか etc… また、他のライブラリでチェックツールは色々とあるかと思いますが、今回はIRISの中だけで完結させており、 チェックだけでなくエラーが出なかった時はコンパイルまで通るところがやはり良い部分に感じました。 今回使用したクラスはGithubにアップしておりますので、興味のある方はご確認いただければと思います。 追記)インデントチェッククラスをEmbedded Pythonで記載してみました。(Githubにもアップしております)

Class User.Chk.IndentCheckerP Extends %RegisteredObject
{

///  処理概要   :インデント不正チェック
///  <br>IN     :clsDef : クラス定義
///  <br>OUT    :%Boolean
///  <br>処理詳細:インデントが4の倍数になっているかをチェックをする。
ClassMethod UseWrongIndentP(clsDef As %Dictionary.ClassDefinition) As %Boolean [ Language = python ]
{
	import iris
	import re
	
	print("*インデント不正チェック\n")
	
	isCorrect = 1
	count = clsDef.Methods.Count()
	for i in range(count):
	    cnt = 0
	    method = clsDef.Methods.GetAt(i + 1)
	    while not method.Implementation.AtEnd:
	        cnt += 1
	        line = method.Implementation.ReadLine()
	        if line == '':
	            continue
	        if len(re.compile("^( {4}){1,}[^ ].*").findall(line)) == 0:
	            isCorrect = 0
	            print("E: インデントが4の倍数になっていません。: " + method.Name + str(cnt) + str(line) + "\n") 
	return isCorrect
}

}

以上になります。ご一読いただき、ありがとうございました。

0
0 165
記事 Toshihiko Minamoto · 10月 14, 2024 16m read

CI/CD シリーズの新しい章へようこそ。ここでは、InterSystems テクノロジーと GitLab を使用したソフトウェア開発の様々な可能なアプローチを取り上げています。

今回は、相互運用性についてご紹介しましょう。

問題

アクティブな相互運用性プロダクションがある場合、2 つの個別のプロセスフローが存在します。メッセージを処理する稼動中のプロダクションと、コード、プロダクションの構成、およびシステムデフォルト設定を更新する CI/CD プロセスフローです。

明らかに、CI/CD プロセスは相互運用性に影響しますが、 本題は次にあります。

  • 更新中には実際に何が起きているのか?
  • 更新中の本番停止を最小限に抑えるか失くしてしまうには、どうすればよいのか?

用語

  • ビジネスホスト(BH)- 相互運用性プロダクションの構成可能な要素: ビジネスサービス(BS)、ビジネスプロセス(BP、BPL)、ビジネスオペレーション(BO)。
  • ビジネスホストジョブ(ジョブ)- ビジネスホストのコードを実行し、相互運用性プロダクションによって管理される InterSystems IRIS ジョブ。
  • プロダクション - 相互に接続されたビジネスホストのコレクション。
  • システムデフォルト設定(SDS)- InterSystems IRIS がインストールされている環境に固有の値。
  • アクティブメッセージ - 1 つのビジネスホストジョブによって現在処理されているリクエスト。 1 つのビジネスホストジョブに対するアクティブメッセージは最大 1 つです。 アクティブメッセージのないビジネスホストジョブはアイドルです。

何が起きているのか?

プロダクションのライフサイクルから見てみましょう。

プロダクションの起動

まず初めに、プロダクションを起動できます。 ネームスペースあたり 1 つのプロダクションのみを同時に実行でき、一般に(作業内容や過程を十分に理解していない限り)、ネームスペースごとに実行するプロダクションは 1 つ限りです。 1 つのネームスペース内で 2 つ以上の異なるプロダクションを切り替えるのは推奨されません。 プロダクションを起動すると、そのプロダクションに定義されたすべての有効なビジネスホストが起動します。 一部のビジネスホストが起動に失敗してもプロダクションの起動には影響しません。

ヒント:

  • システム管理ポータルから、または ##class(Ens.Director).StartProduction("ProductionName") を呼び出してプロダクションを起動します。
  • OnStart メソッドを実装して、プロダクションの起動時に(ビジネスホストジョブが起動する前に)任意のコードを実行します。
  • プロダクションの起動は監査可能なイベントです。 誰がいつ起動したかを必ず監査ログで確認できます。

プロダクションの更新

プロダクションが起動した後、Ens.Director は実行中のプロダクションを継続的に監視します。 プロダクションの状態は 2 つあります。プロダクションクラスとシステムデフォルト設定に定義された target state と、ジョブが作成されたときに適用された設定で現在実行しているジョブの running state です。 希望する状態と現在の状態が同一である場合はすべて良好ですが、異なる場合にはプロダクションを更新する必要があります。 通常、この場合には、システム管理ポータルのプロダクション構成ページに赤い「更新」ボタンが表示されます。

プロダクションを更新すると、現在のプロダクションの状態をターゲットプロダクションの状態に一致させることになります。

プロダクションを更新するために ##class(Ens.Director).UpdateProduction(timeout=10, force=0) を実行すると、各ビジネスホストにおいて以下が行われます。

  1. アクティブな設定をプロダクション/SDS/クラスの設定と比較します。
  2. (1) で不一致が生じた場合に限り、ビジネスホストは古いものとしてマークされ、更新が必要となります。

これを各ビジネスホストに対して実行した後、UpdateProduction は一連の変更をビルドします。

  • ビジネスホストを停止
  • ビジネスホストを起動
  • プロダクション設定を更新

そしてその後で適用します。

このようにして、何も変更せずに設定を「更新」するとプロダクションが停止しません。

ヒント:

  • システム管理ポータルから、または ##class(Ens.Director).UpdateProduction(timeout=10, force=0) を呼び出してプロダクションを更新します。 システム管理ポータルのデフォルトの更新タイムアウトは 10 秒です。 メッセージの処理がそれ以上かかることが分かっている場合は、タイムアウト時間がより長い Ens.Director:UpdateProduction を呼び出します。
  • 更新タイムアウトはプロダクションの設定であり、より長い時間に値を変更できます。 この設定はシステム管理ポータルに適用されます。

コードの更新

UpdateProduction は古いコードで BH を更新することはありません。 これは安全を優先した動作ではありますが、根底にあるコードが変更した場合にすべての実行中の BH を自動的に更新する場合は、以下のように行います。

まず、以下のように読み込んでコンパイルします。

do $system.OBJ.LoadDir(dir, "", .err, 1, .load)
do $system.OBJ.CompileList(load, "curk", .errCompile, .listCompiled)

listCompiled には、u フラグにより、実際にコンパイルされたすべての項目が含まれます(読み込まれるセットを最小限に抑えるには、git diffs を使用します)。 この listCompiled を使用して、コンパイルされたすべてのクラスの $lb を取得します。

set classList = ""
set class = $o(listCompiled(""))
while class'="" { 
  set classList = classList _ $lb($p(class, ".", 1, *-1))
  set class=$o(listCompiled(class))
}

その後で、再起動が必要な BH のリストを計算します。

SELECT %DLIST(Name) bhList
FROM Ens_Config.Item 
WHERE 1=1
  AND Enabled = 1
  AND Production = :production
  AND ClassName %INLIST :classList

最後に、bhList を取得した後に、影響のあるホストを停止して起動します。

for stop = 1, 0 {
  for i=1:1:$ll(bhList) {
    set host = $lg(bhList, i)
    set sc = ##class(Ens.Director).TempStopConfigItem(host, stop, 0)
  }
  set sc = ##class(Ens.Director).UpdateProduction()
}

プロダクションの停止

プロダクションは停止可能です。つまり、すべての美自演すホストジョブにシャットダウンのリクエストを送信します(アクティブなメッセージがある場合はその処理が完了してから安全にシャットダウンされます)。

ヒント:

  • システム管理ポータルから、または ##class(Ens.Director).StopProduction(timeout=10, force=0) を呼び出してプロダクションを停止します。 システム管理ポータルのデフォルトの停止タイムアウトは 120 秒です。 メッセージの処理がそれ以上かかることが分かっている場合は、タイムアウト時間がより長い Ens.Director:StopProduction を呼び出します。
  • シャットダウンタイムアウトはプロダクションの設定です。 より長い時間に値を変更できます。 この設定はシステム管理ポータルに適用されます。
  • OnStop メソッドを実装して、プロダクションの停止時に任意のコードを実行します。
  • プロダクションの停止は監査可能なイベントであり、誰がいつ停止したのかを必ず監査ログで確認できます。

ここで重要なのは、プロダクションはビジネスホストの合計であることです。

  • プロダクションを起動するとすべての有効なビジネスホストが起動します。
  • プロダクションを停止するとすべての実行中のビジネスホストが停止します。
  • プロダクションを更新すると、古いセットのビジネスホストが計算され、これらが先に停止されてからその直後にもう一度起動されます。 また、新たに追加されたビジネスホストは開始のみされ、プロダクションから削除されたビジネスホストは単に停止されます。

この流れで、ビジネスホストのライフサイクルに進みましょう。

ビジネスホストの起動

ビジネスホストは(プールサイズの設定値に応じて)同一のビジネスホストジョブで構成されています。 ビジネスホストを起動すると、すべてのビジネスホストジョブが起動します。 これらは並列して起動します。

個別のビジネスホストジョブは以下のように起動します。

  1. 相互運用性はビジネスホストジョブになる新しいプロセスを JOB で起動します。
  2. 新しいプロセスは相互運用性ジョブとして登録されます。
  3. ビジネスホストコードとアダプターコードがプロセスメモリに読み込まれます。
  4. ビジネスホストとアダプターに関連する設定がメモリに読み込まれます。 以下はその順序です。 a. プロダクション設定(システムデフォルトとクラス設定をオーバーライドします)。 b. システムデフォルト設定(クラス設定をオーバーライドします)。 c. クラス設定。
  5. ジョブの準備が整い、メッセージを受け入れ始めます。

(4)が完了すると、ジョブは設定またはコードを変更できないため、新しい/同じコードと新しい/同じシステムデフォルト設定をインポートしても、現在実行中の相互運用性ジョブに影響しません。

ビジネスホストの停止

ビジネスホストジョブを停止すると、以下のようになります。

  1. 相互運用性はジョブにメッセージ/入力の受け入れ停止を要求します。
  2. アクティブなメッセージがある場合、ビジネスホストジョブにはそれを処理するための数秒のタイムアウトがあります(ジョブを完了、つまり BO の場合は OnMessage メソッド、BS の場合は OnProcessInput メソッド、BPL BP の場合は状態の S<int> メソッド、BP の場合は On*メソッドを終了します)。
  3. アクティブなメッセージがタイムアウトと force=0 までに処理されていない場合、そのビジネスホストのプロダクションの更新は失敗します(SMP に赤い更新ボタンが表示されます)。
  4. 以下のいずれかを満たす場合は停止します。
    • アクティブなメッセージがない
    • アクティブなメッセージは timeout の前に処理された
    • アクティブなメッセージはタイムアウト前に処理されなかったが force=1 で処理された
  5. ジョブは 相互運用性から登録解除され停止します。

ビジネスホストの更新

ビジネスホストの更新では、ビジネスホストの現在実行中のジョブを停止し、新しいジョブを起動します。

ビジネスルール、ルーティングルール、DTL

すべてのビジネスホストは、新しいバージョンのビジネスルール、ルーティングルール、および DTL が利用できるようになると直ちにそれらを使用し始めます。 この状況では、ビジネスホストの再起動は不要です。

オフラインでの更新

とは言え、時にはプロダクションの更新には個別のビジネスホストの停止が必要です。

ルールは新しいコードで決まる

この状況を考えてみてください。 任意の基準に基づいてメッセージをビジネスプロセス A または B にルーティングする現在のルーティングルール X があるとします。 新しいコミットにおいて、以下を同時に追加します。

  • ビジネスプロセス C
  • メッセージを A、B、または C にルーティングする新しいバージョンのルーティングルール X

このシナリオでは、先にルールを読み込んでからプロダクションを更新することはできません。 新しくコンパイルされるルールは、InterSystems IRIS がまだコンパイルしていないかもしれないビジネスプロセス C に直ちにルーティングし始めるか、相互運用性がまだ使用できるように更新されていないためです。 この場合、ルーティングルールでビジネスホストを無効に子、コードを更新し、プロダクションを更新して、ビジネスホストをもう一度有効にする必要がります。

注意:

  • プロダクションデプロイファイルを使用してプロダクションを更新する場合、影響されるすべての BH は自動的に無効化/有効化されます。
  • InProc によって呼び出されたホストの場合、コンパイルによって呼び出し元が保持する特定のホストのキャッシュが無効になります。

ビジネスホスト間の依存関係

ビジネスホスト間の依存関係は重要です。 ビジネスプロセス A と B があり、A が B にメッセージを送信するとします。 新しいコミットにおいて、以下を同時に追加します。

  • リクエストの新しいプロパティX を B に設定する新しいバージョンのプロセス A
  • 新しいプロパティ X を処理できる新しいバージョンのプロセス B

このシナリオでは、プロセス B を先に更新してから A を更新する必要があります。 これは次のいずれかの方法で行えます。

  • 更新の間、ビジネスホストを無効化する
  • 更新を 2 つに分ける: まずプロセス B のみを更新してから、その後の別の更新で、プロセス A から B にメッセージを送信し始める。

新しいバージョンのプロセス A と B に古いバージョンとの互換性がない場合のより困難な状況では、ビジネスホストの停止が必要となります。

キュー

更新後に、ビジネスホストが古いメッセージを処理できないことが分かっている場合、ビジネスホストキューが更新前に空になっていることを確認する必要があります。 これを行うには、ビジネスホストにメッセージを送信するすべてのビジネスホストを無効化し、そのキューが空になるのを待ちます。

BPL ビジネスプロセスにおける状態の変更

はじめに、BPL BP の仕組みから簡単に説明します。 BPL BP をコンパイルした後、2 つのクラスが完全な BPL クラス名と同じ名前でパッケージに作成されます。

  • Thread1 クラスはメソッド S1, S2, ... Sn を含み、BPL 内のアクティビティに対応します。
  • Context クラスにはすべてのコンテキスト変数があり、BPL が実行する次の状態もあります(S5)・

また BPL クラスは永続であり、現在処理中のリクエストを格納します。

BPL は Thread クラスで S メソッドを実行し、それにおうじて BPL クラステーブル、Context テーブル、および Thread1テーブルを更新することによって機能します。ここで、「処理中」の 1 つのメッセージは BPL テーブル内の 1 行になります。 リクエストが処理されると、BPL は BPL、Context、および Thread エントリを削除します。 BPL BP は非同期であるため、1 つの BPL ジョブは S 呼び出しの間に情報を保存して異なるリクエストを切り替えることで、同時に多数のリクエストを処理できます。 たとえば、BPL は 1 つのリクエストが sync アクティビティに到達するまで処理し、BO からの応答を待ちます。 現在のコンテキストを %NextState プロパティ(Thread1 クラス)をレスポンスアクティビティ S メソッドに設定してディスクに保存し、BO が応答するまで他のリクエストを処理します。 BO が応答したら、BPL はコンテキストをメモリに読み込んで、%NextState プロパティに保存された状態に対応するメソッドを実行します。

では、BPL を更新したらどうなるでしょうか? まず、少なくとも以下の 2 つの条件の 1 つを満たしていることをチェックする必要があります。

  • 更新中に、Context テーブルが空である。つまり、処理中のアクティブなメッセージがない。
  • 新しい状態は古い状態と同じであるか、新しい状態は古い状態の後に追加されている。

少なくとも 1 つの条件を満たしている場合は、問題ありません。 更新後 BPL が処理する更新前リクエストが存在しないか、状態が最後に追加される、つまり古いリクエストもそこに含まれることが可能です(更新前リクエストが更新後 BPL アクティビティと処理に互換していることが前提です)。

ただし、処理中のアクティブなリクエストが存在し、BPL が状態の順序を変更した場合はどうでしょうか? 理想的には、待機できるのであれば、BPL 呼び出し元を無効にしてキューが空になるまで待機します。 Context テーブルが空であることも確認します。 キューには未処理のリクエストのみが表示され、Context テーブルは処理中のリクエストを格納することを覚えておきましょう。つまり、非常にビジーな BPL のキューサイズが 0 となる場合があり、それは正常です。 その後、BPL を無効にし、更新を実行して、以前に無効にしたすべてのビジネスホストを有効にします。

それが可能でない場合は(通常、非常に時間のかかる BPL がある場合。リクエストの処理に約 1 週間かかった BPL の更新ケースや更新ウィンドウが短すぎたケースを覚えています)、BPL バージョン管理を使用します。

または、更新スクリプトを書くことができます。 この更新スクリプトでは、更新された BPL が古いリクエストを処理できるように、古い次の状態を新しい次の状態にマッピングして、Thread1 テーブルで実行します。 もちろん更新期間中は BPL を無効にしておく必要があります。 とは言え、これは非常にまれな状況であり、通常は行う必要はありませんが、その必要性が生じた場合にはこれを使用することができます。

まとめ

相互運用性は、根底にあるコードが変更した後でプロダクションを最新状態にするために必要となるアクションを最小限に抑えるために、洗練されたアルゴリズムを実装します。 SDS の更新ごとに安全なタイムアウトで UpdateProduction を呼び出せます。 それぞれのコードの更新については更新ストラテジーを決定する必要があります。

git diffs を使ってコンパイルされるコードの量を最小限に抑えると、コンパイル時間の軽減に役立ちますが、コードをそのコード自体で「更新」して再コンパイルするか、同じ値で設定を「更新」するとプロダクションの更新はトリガーされないか不要となります。

ビジネスルール、ルーティングルール、および DTL を更新してコンパイルすると、プロダクションを更新せずにすぐにアクセス可能になります。

最後に、プロダクションの更新は安全な操作であり、通常、停止は必要ありません。

リンク

この記事の執筆において貴重な支援を提供してくださった @James MacKeith@Dmitry Zasypkin、および @Regilo Regilio Guedes de Souza に感謝申し上げます。

0
0 60
記事 So Ochi · 10月 13, 2024 10m read

はじめに

生成AIを活用したアプリケーション開発は、Python、JavaScriptなどのメジャー言語による体験記事がよく見られます。一方、IRISのObjectScriptの開発に言及された記事は比較的少ないのが現状です。そこで、本記事では生成AIがObjectScriptの開発にどこまで活用できるのかを検証しました。

特にDevOpsのプロセスにおいて、生成AIは様々なシーンでの活用が期待できます。今回は開発工程に注目し、以下の観点から生成AIの有効性を調査しました。

  • 開発
    • コードの自動生成
    • 環境構築のアシスタント(テーブルの作成)
  • 検証
    • テストデータ生成のサポート

環境

本記事の検証は以下の環境で行いました。

開発環境

  • OS: macOS Sonoma
  • IRIS: 2023.4 (linux)

開発ツール IRISの開発にはStudioやVSCodeなどが利用可能ですが、今回は生成AIの活用に特化したエディタ「Cursor」を使用しました。

Cursorを選定した理由 Cursorは、生成AIによる支援機能に特化したコードエディタで、以下の特徴があります:

  • 生成AIの支援:コードの自動生成や提案、バグの検出、修正提案を行います。また、外部のドキュメントや複数のソースを指定し、生成内容に反映させる簡易なRAG機能も搭載されています。

  • VSCodeとの互換性:VSCodeをフォークして作られており、VSCodeユーザーはスムーズに移行できます。拡張機能もそのまま利用可能です。

IRISではv2024よりStudioは廃止となり、VSCodeが標準ツールとなります。そこで、VSCodeと互換性があり、生成AIとの親和性が高いCursorを選定しました。

選択した生成AIモデル GPT-4を使用しましたが、Claudeでも検証を行ったところ、どのモデルも大差ない結果となりました。 利用しやすいモデルを選んで試してみてください。

検証内容

今回は以下の内容を検証しました。

  • 簡単なプログラムの生成とターミナルでの実行
  • IRISのREST通信機能を使った商品情報検索APIの作成

サンプルプログラムの作成

まず、ユーザーに名前を入力させ、挨拶を返す簡単なルーチンを生成します。CursorでCommand+Lを押してチャットウィンドウを開き、以下のプロンプトを入力します。

あなたはObjectScriptの開発者です。
{仕様}をもとにコードを作成してください。
#仕様
- 以下の処理を実行するRoutineを作成する。
- macファイル名は"TEST.mac"とする。
1. ユーザーに名前の入力を促します。
2. 入力された名前が空であればエラーメッセージを表示します。
3. 名前が入力された場合、その名前を使って挨拶メッセージを表示します。

image

生成されたルーチンをTEST.macにコピーし、ターミナルで実行して動作を確認します。

image

REST APIの作成

簡易なプログラムの生成が確認できたので、次はより複雑なアプリケーションを作成してみます。

アプリケーションの仕様 IRISのREST通信機能を利用したAPIを作成します。ユーザーからのリクエストに基づき、サーバー上のデータベースから該当する商品情報をJSON形式で返します。

テーブルの作成 まずは、テーブルを作成しましょう。DDLの作成をAIに依頼します。

InterSystemsのIRISで{テーブル}を作成するためのDDLを出力してください
#テーブル
##名前
- Sample.Product
##列
- JanCd VARCHAR(13)
- ProductName VARCHAR(100)
- Price INT
## プライマリキー
- JanCd

image

生成されたDDLをターミナルから実行し、テーブルが正常に作成されたことを確認します。

image

テストデータの作成 テストデータの作成もAIにアシストしてもらいましょう。

image

テストデータが正常に登録されたことを確認します。

image

APIの作成 準備が整ったので、APIクラスを生成します。以下のプロンプトを使ってコードを作成します。

あなたはObjectScriptの開発者です。
{仕様}をもとに"Api.Product"クラスを作成してください。
#仕様
- REST通信でJSON形式で商品情報を返す。
- apiのURLは/products/:jancd
- %CSP.RESTクラスを継承する。
- Jsonデータの生成は%DynamicObjectクラスを利用する。
- レスポンスコードは、%responseを利用する。
1. jancdが指定されなかった場合、404を返す。指定された場合、以降の処理を続行する。 
2. "Sample.Product"テーブルをSQLで検索する。
- 取得項目: JanCd,ProductName,Price
- 検索条件: :jancdが指定された場合、テーブルをJanCdが一致するレコードを検索する。
3. 検索結果をJSON形式でREST通信結果として出力する。

image

生成されたコードを確認し、必要に応じて修正を加えます。クエリ結果の取得箇所で%Next()が実行されていなかったため、以下の修正を行いました。

Set tResult = tStatement.%Execute(jancd)
// -*-*-*-*- 処理を追加しました -*-*-*-*-
Do tResult.%Next()

If tResult.%SQLCODE = 100 {

curlコマンドを使用してAPIの動作を確認し、正常にJSONデータが返却されることを確認します。

image

最終的なソースは以下の通りです。今回は一部修正が必要でしたが、基本的な部分は生成AIが正しく対応していました。

  Class Api.Product Extends %CSP.REST
  {

  /// URLマッピング
  XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
  {
  <Routes>
      <Route Url="/products/:jancd" Method="GET" Call="GetProductInfo"/>
  </Routes>
  }

  /// 商品情報を取得するメソッド
  ClassMethod GetProductInfo(jancd As %String) As %Status
  {
      // jancdが指定されていない場合、404を返す
      If jancd = "" {
          Set %response.Status = 404
          Quit $$$OK
      }

      // "Sample.Product"テーブルをSQLで検索する
      Set tStatement = ##class(%SQL.Statement).%New()
      Set tSQL = "SELECT JanCd, ProductName, Price FROM Sample.Product WHERE JanCd = ?"
      Set tStatus = tStatement.%Prepare(tSQL)
      
      If $$$ISERR(tStatus) {
          Set %response.Status = 500
          Quit tStatus
      }
      
      Set tResult = tStatement.%Execute(jancd)
      Do tResult.%Next()
      
      // 検索結果がない場合、404を返す
      If tResult.%SQLCODE = 100 {
          Set %response.Status = 404
          Quit $$$OK
      }
      
      // 検索結果をJSON形式で出力する
      Set tProduct = ##class(%DynamicObject).%New()
      Do tProduct.%Set("JanCd", tResult.%Get("JanCd"))
      Do tProduct.%Set("ProductName", tResult.%Get("ProductName"))
      Do tProduct.%Set("Price", tResult.%Get("Price"))
      
      Write tProduct.%ToJSON(),!
      
      Quit $$$OK
  }

  }

既存コードの活用

次に、生成したAPIに商品名を部分一致で検索するメソッドを追加します。Cursorの外部ファイル参照機能を使い、先ほど生成したクラスを参考にしながら新しいメソッドを作成します。プロンプトは以下の通りです。

@Api.Product.cls 
以下の{仕様}で、"Api.Product"クラスにメソッドを追加してください。
#仕様
- GetProductInfo()の処理を参考にすること。
- apiのURLは/products/name/:productname
- Sample.ProductテーブルからAPIで指定された値が、ProductNameと部分一致するレコードを検索し、検索した結果をJson形式で返す。
- 検索結果は配列にして返す。

image

生成したコードは以下になります。(追加部分のみ抜粋)

  Class Api.Product Extends %CSP.REST
  {
      // ... 既存のコード ...

      /// URLマッピング
      XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
      {
      <Routes>
          // ... 既存のルート ...
          <Route Url="/products/name/:productname" Method="GET" Call="GetProductInfoByName"/>
      </Routes>
      }

      // ... 既存のコード ...

      /// 商品名で商品情報を取得するメソッド
      ClassMethod GetProductInfoByName(productname As %String) As %Status
      {
          // productnameが指定されていない場合、404を返す
          If productname = "" {
              Set %response.Status = 404
              Quit $$$OK
          }

          // "Sample.Product"テーブルをSQLで検索する
          Set tStatement = ##class(%SQL.Statement).%New()
          Set tSQL = "SELECT JanCd, ProductName, Price FROM Sample.Product WHERE ProductName LIKE ?"
          Set tStatus = tStatement.%Prepare(tSQL)
          
          If $$$ISERR(tStatus) {
              Set %response.Status = 500
              Quit tStatus
          }
          
          Set tResult = tStatement.%Execute("%" _ productname _ "%")
          
          // 検索結果がない場合、404を返す
          If tResult.%SQLCODE = 100 {
              Set %response.Status = 404
              Quit $$$OK
          }
          
          // 検索結果をJSON形式で出力する
          Set tProducts = ##class(%DynamicArray).%New()
          While tResult.%Next() {
              Set tProduct = ##class(%DynamicObject).%New()
              Do tProduct.%Set("JanCd", tResult.%Get("JanCd"))
              Do tProduct.%Set("ProductName", tResult.%Get("ProductName"))
              Do tProduct.%Set("Price", tResult.%Get("Price"))
              Do tProducts.%Push(tProduct)
          }
          
          Write tProducts.%ToJSON(),!
          
          Quit $$$OK
      }

      // ... 既存のコード ...
  }

生成されたコードを確認し、curlコマンドで動作を確認します。正常に実行されました。外部ファイル参照機能の利用により、自動生成の精度が向上していることがうかがえます。 image

開発上の課題と解決策

自動生成の精度向上 基本コマンドを用いたプログラムは高い精度を発揮しますが、クラスを利用した複雑な処理では精度が低下する印象を受けました。プロンプトの指示を工夫することで、精度を高めることができそうです。 また、Cursorの外部ドキュメント、ファイル参照機能には大きな可能性を感じました。この機能を使えば、既存のリソースや、AIが学習していないライブラリの活用が期待できます。

セキュリティとプライバシー Cursorはプライバシーモードを備えており、データをサーバーに保持しない設定が可能です。しかし、Cursorに限らず生成AIの業務利用には慎重な調査が必要です。

所感

今回の検証を通じて、生成AIのコード生成能力が向上していることを実感しました。特に、テストデータやDDLの生成は、開発の効率を大幅に向上させる可能性があります。アジャイル開発で迅速なモックアップの作成が求められる場面では、生成AIの効果的な活用が期待できそうです。一方で、既存システムの小規模な改修には、効果が限定的であるという印象を受けました。

この記事を作成したきっかけは、ObjectScriptの初学者向け演習問題を生成AIで作成した際、その問題と解答の品質が非常に高かったことです。業務での活用も十分可能であると思い、今回の検証を行いました。生成AIは、工夫次第でさらなる幅広い活用が期待できるツールだと感じています。

参考資料

0
0 249
記事 Toshihiko Minamoto · 10月 8, 2024 9m read

約 4 年のギャップを経て、私の CI/CD シリーズが帰ってきました! 長年にわたり、InterSystems の数社のお客様と連携し、様々なユースケースに対応する CI/CD パイプラインを開発してきました。 この記事で紹介する情報が誰かのお役に立てられれば幸いです。

この連載記事では、InterSystems テクノロジーと GitLab を使用したソフトウェア開発の様々な可能なアプローチを取り上げています。

取り上げたいトピックは広範にありますが、今回は、コードを超えた内容についてお話ししましょう。構成とデータについてです。

問題

前回はコードの昇格について話しました。ある意味ステートレスで、常に、(おそらく)空のインスタンスから完全なコードベースへと進めます。 ただし、時にはデータまたは状態を提供することも必要です。 データには様々なタイプがあります。

  • 構成: ユーザー、ウェブアプリ、LUT、カスタムスキーマ、タスク、ビジネスパートナーなど
  • 設定: 環境固有の key-value ペア
  • データ: 参照テーブルとアプリが機能するために提供しなければならない場合があるテーブル

これらすべてのデータタイプについて、およびソース管理にコミットしてからデプロイする方法について説明します。

構成

システム構成は多数のクラスに広がっていますが、InterSystems IRIS はほとんどを XML にエクスポートできます。 まず最初に、これは以下についての情報を含むSecurityパッケージです。

  • Web アプリケーション
  • DocDB
  • ドメイン
  • 監査イベント
  • KMIPServers
  • LDAP 構成
  • リソース
  • ロール
  • SQL 特権
  • SSL 構成
  • サービス
  • ユーザー

これらのすべてのクラスは Exists、Export、および Import メソッドを提供しているため、環境間で移動することが可能です。

いくつかの欠点:

  • ユーザーと SSL 構成にはパスワードなどの機密情報が含まれる場合があります。 セキュリティ上の理由により、通常はこれらをソース管理に保存することは推奨されません。 1 回限りの転送を行うには Export/Import メソッドを使用します。
  • Export/Import メソッドはデフォルトですべてを 1 つのファイルに出力するため、ソース管理には不便である場合があります。 ルックアップテーブル、カスタムスキーマ、ビジネスパートナー、タスク、認証情報、および SSL 構成のエクスポートとインポートを行えるユーティリティクラスがあります。 これはファイル当たり 1 つの項目をエクスポートするため、LUT を含むディレクトリ、カスタムスキーマのディレクトリ、などを得ることができます。 SSL 構成の場合は、証明書やキーといったファイルもエクスポートします。

また、Export/Import の代わりに %Installer または Merge CPF を使用してこれらのほとんどを作成できることも覚えておくとよいでしょう。 いずれのツールもネームスペースとデータベースの作成をサポートしています。 Merge CPF はグローバルバッファーサイズなどのシステム設定を調整できます。

タスク

%SYS.Task クラスはタスクを保管し ExportTasks および ImportTasks メソッドを提供します。 また、タスクを 1 つずつインポート/エクスポートするには、上記のユーティリティクラスも確認してください。 タスクをインポートする際に StartDate またはその他のスケジュール関連のプロパティが過去の日時である場合、インポートエラー(ERROR #7432: Start Date and Time must be after the current date and time)が発生する可能性があることに注意しましょう。 ソリューションとして、LastSchedule0 に設定すると、InterSystems IRIS は新たにインポートしたタスクを最も近い未来に実行するようにスケジュールを設定し直します。

相互運用性

相互運用性本番には以下が含まれます。

  • ビジネスパートナー
  • システムのデフォルト設定
  • 認証情報
  • ルックアップテーブル

最初の 2 つは Ens.Config パッケージにあり、%Export%Import メソッドを使用できます。 認証情報とルックアップテーブルは上記のユーティリティクラスを使ってエクスポートします。 最近のバージョンでは、ルックアップテーブルは $system.OBJ クラスでエクスポート/インポートできます。

設定

システムデフォルト設定 - 環境固有の設定のデフォルトの相互運用性メカニズムです。

システムデフォルト設定の目的は、本番定義を環境間でコピーするプロセスを単純化することにあります。 いずれのプロダクションにおいても、いくつかの設定の値はプロダクションの設計の一部として決定されます。そのためこれらの設定は通常すべての環境で同一です。 一方でその他の設定は、環境に合わせて調整する必要があり、これらの設定にはファイルパス、ポート番号などが含まれます。

システムデフォルト設定は、InterSystems IRIS がインストールされている環境に固有の値のみを指定する必要があります。 それに反し、プロダクションの定義では、すべての環境で同一となる設定の値を指定する必要があります。

これらを本番環境で使用することを非常にお勧めします。 システムデフォルト設定を転送するには、%Export%Import を使用してください。

アプリケーション設定

アプリケーションもおそらく設定を使用します。 その場合、システムデフォルト設定を使用することをお勧めします。 これは相互運用性メカニズムではありますが、設定は %GetSetting(pProductionName, pItemName, pHostClassName, pTargetType, pSettingName, Output pValue)ドキュメント)からアクセスできます。 必要でないデフォルト設定を設定するラッパーを書くことができます。例:

ClassMethod GetSetting(name, Output value) As %Boolean [Codemode=expression]
{
##class(Ens.Config.DefaultSettings).%GetSetting("myAppName", "default", "default", , name, .value)
}

ほかにもカテゴリが必要な場合は、pItemNamepHostClassName 引数を公開することもできます。 設定は主に、インポート、システム管理ポータルの使用、Ens.Config.DefaultSettings クラスのオブジェクトの作成、または ^Ens.Config.DefaultSettingsD グローバルの設定によって設定できます。

ここでの主なアドバイスは、設定を 1 か所にまとめておき(システムデフォルト設定またはカスタムソリューションのどちらでもかまいません)、アプリケーションは指定された API のみを使用して設定を取得するようにすることです。 この場合、アプリケーション自体は環境について認識せず、残っているのは環境固有の値を含む集中設定ストレージを提供することだけです。 これを行うには、リポジトリに環境ブランチ名と同じファイル名で設定ファイルを含む設定フォルダを作成します。 次に、CI/CD フェーズにおいて、$CI_COMMIT_BRANCH環境変数を使って正しいファイルを読み込みます。

DEV.xml
TEST.xml
PROD.xml

環境ごとに複数のファイルがある場合は、環境ブランチに因んだフォルダ名を使用してください。 InterSystems IRIS 内部から環境変数値を取得するには、$System.Util.GetEnviron("name")使用します

データ

一部のデータ(参照テーブル、カタログなど)を使用できるようにするには、いくつかの方法があります。

  • グローバルエクスポート。 バイナリ GOF export または新しい XML エクスポートをのいずれかを使用します。 GOF エクスポートの場合は、ソースとターゲットシステムのロケールが一致する(または少なくともグローバルこれ―ションがターゲットシステムで使用できる)必要があることに注意しましょう。 XML エクスポート にはさらに多くの空き容量が必要です。 グローバルを xml.gz ファイルにエクスポートし、$system.OBJ メソッドが必要に応じて xml.gz ファイルを自動的にアーカイブ(アーカイブ解除)するようにすることで改善できます。 このアプローチの主なデメリットは、XML であってもほとんどが base64 でエンコードされるため、データを人間が読み取れないことです。
  • CSV。 CSV をエクスポートして、LOAD DATA でインポートします。 CSV は最もストレージ効率が高く人間が読み取れる形式であるため、私の一番の優先オプションです。何にでもインポートできます。
  • JSON。 クラスを JSON 対応にします。
  • XML。 オブジェクトを XML に投影するためにクラスを XML 対応にします。 データに複合構造が含まれる場合に使用します。

どの形式を使用するかは、ユースケースによって異なります。 ここでは、ストレージ効率の順に形式をリストしていますが、データ量があまり多くない場合には考慮する点ではありません。

まとめ

状態は、CI/CD デプロイパイプラインをさらに複雑にしますが、InterSystems IRIS ではそれを管理するためのツールを豊富に提供しています。

リンク

0
0 81
お知らせ Mihoko Iijima · 9月 6, 2024

開発者のみなさん、こんにちは!

今年も開発者コミュニティミートアップを東京にて開催いたします!(10月1日:お申込みサイトオープンいたしました!)

日 時:2024年11月8日(金)13時半~19時

場 所:AP東京八重洲 13階

<JR各線をご利用の場合>「東京駅」八重洲中央口より徒歩6分
<東京メトロ銀座線をご利用の場合>「日本橋駅」徒歩約5分/「京橋駅」徒歩約4分
<都営浅草線をご利用の場合>「宝町駅」徒歩約4分

※ヤエチカ24番出口から出るとわかりやすいです。
 

参加費:無料

定 員:50名
※定員に達した際は調整をお願いすることもございます。予めご了承下さい。

申 込:(申込受付終了しました)

3
0 388
記事 Akio Hashimoto · 10月 4, 2024 3m read

IRISはPythonの豊富なライブラリや既存のPythonプログラムをそのまま利用する事も、COS内でネイティブにコーディングする事も可能となりました。 しかし開発において、いくつかの問題点があります。

1. Pythonのバージョン

Pythonを使ったプロジェクトを構築していると、バージョンの問題にあたる時があります。 古いバージョンで開発していたところに、使いたいライブラリが対応していなかった等です。 しかし、IRISのEmbedded Pythonを利用する場合には、Pythonランタイムのバージョンに影響される為、プロジェクトで使用するバージョンは、プロジェクト単位はなく、IRISのバージョン単位で決まってしまいます。 また、現時点ではこのPythonランタイムをアップグレードする事はできません。

2. 外部Pythonファイルの利用

私は既に開発済みのPythonプログラムをそのまま活用したいと思い、外部Pythonファイルを読み込んで利用する方法を取りました。 IRISでは外部Pythonファイルを特定の場所に配置する事で、そのファイルをimportする事が出来ます。 デフォルトは{インストールパス}/lib/python です。 しかし、デフォルトではこの1ヶ所のディレクトリが対象となっていて、さらにサブフォルダは対象外となる為、プロジェクト単位などで管理する事も出来ません。

Python対象パスを指定

PythonPathの値を変更する事で、別のディレクトリを指定できます。 また、複数のディレクトリを指定する事も可能です。 Windowsであればカンマ区切り、linux等であればコロン区切りで複数指定が可能です。 但し、間にスペースを入れると認識されませんので注意して下さい。 また、複数ディレクトリに同じ名前のモジュールが存在すると、最初に読み込まれた物を利用するようです。(筆者実体験から) また、このPythonPathの値は、Pythonの対象ディレクトリを指定した場所だけに変更するのではなく、デフォルトのディレクトリに追加される事に注意して下さい。 PythonPathを書き換えてもデフォルトのディレクトリは読み込まれています。 もしデフォルトのディレクトリに同じ名前のPythonファイルがあると、そちらが先にimportされるようなので注意が必要です。

PythonPathの指定 image ここに記載されていないが、デフォルトのディレクトリも対象となている。

複数指定する場合は、スペースを入れない /opt/iris/python/common: /opt/iris/python/project --> コロンの後にスペースを入れると認識されない。

3. 修正が反映しない

IRISは外部Pythonファイルやライブラリを読み込むと、プロセスが閉じるまで再読み込みをしません。 ですので、外部Pythonファイルを修正しても即時反映しません。 この場合、プロセスを一度閉じて再実行する必要があります。 ターミナル実行時などであれば、対処法が思いつきますが、Webブラウザからの場合は、セッションが閉じられても再読み込みされません。 Webブラウザからのアクセスの場合は、ウェブゲートウェイを閉じる必要があります。それは結構な手間です。 そこで、即時反映に近い動きにする為には、importしたモジュールをリロードする方法があります。

importlib.reload({モジュール名})

これをCOSの中でモジュールをimportしている箇所に記載する事で、実行する毎にモジュールのリロードを行います。

import importlib
import module1
import module2

importlib.reload(module1)
importlib.reload(module2)

以上が、筆者が最近経験したEmbedded Pythonを利用する時に起こった問題点です。

0
0 416
InterSystems公式 Seisuke Nakahashi · 10月 4, 2024

InterSystems IRIS の新バージョンに、 Hierarchical Navigable Small World (HNSW) インデックス・アルゴリズムに基づく新しい近似最近傍探索 (ANN) インデックスが搭載されました。こちらは、ベクトル検索 早期アクセスプログラム で入手いただけます。これにより、大規模なベクトルデータセットに対して非常に効率の良い近似最近傍探索が可能となり、クエリパフォーマンスとスケーラビリティが大幅に向上しました。

HNSW アルゴリズムは、グラフベース構造を利用して高次元データのベクトル検索を最適化するよう設計されており、大規模なベクトル集合における近似近傍探索を高速化します。HNSW によって、レコメンデーションシステム、自然言語処理、その他の機会学習アプリケーションなどすべてにおいて検索時間が大幅に短縮します。

HNSWの主な利点:

    •    データセットサイズ増加後も、より高速な検索が可能
    •    高精度をたもちながら、メモリ使用量を削減
    •    既存の IRIS ベクトル検索とのシームレスな統合

最新バージョンのトライアル

0
0 186
お知らせ Mihoko Iijima · 10月 1, 2024

開発者の皆さん、こんにちは!

USコミュニティで現在開催しているいつもとちょっと違ったコーディングではないイベント:🚶‍♀️InterSystems ウォーキング・チャレンジ🚶‍♂️をご案内します!

(通勤通学でよく歩いている方、賞品Getのチャンスです!)

InterSystemsのウォーキング・チャレンジは、あなたの心を充電し、フィットネスを高めるのに役立ちます。 リューベックからリューネブルクまで、何世紀も前にヨーロッパを結んだ伝説の交易路「塩の道」を歩くバーチャルな旅に出かけましょう。

そして、トレッドミル、スマートウォッチ、メダルなどのエキサイティングな賞品をゲットしましょう!

👟🚶🧑‍🦼Lace Up, Step Out, and Code Better! 🔋💻💪

📅 期間:2024年9月23日~10月20日 11月8日まで(11月22日18時CETにこのチャレンジは終了します)

参加されたい方、以下詳細をご参照ください。

0
0 82
記事 Saori Murata · 9月 30, 2024 19m read

開発者の皆さん、こんにちは! InterSystems IRIS(以下、IRIS)を使用したアプリケーション開発において、皆さんは環境設定をどうされていますか? 私は最近になって、「インストールマニフェスト」という機能があることを知りました。 これは、管理ポータルでポチポチしていた作業をコード化・自動化できる強力なツールです! 最初こそとっつきづらかったものの良いところがたくさんあるなと思ったので、簡単にではありますが皆さんにその良さと始め方をご紹介したいと思います。

なお、私が使用しているIRISバージョンは以下です。

2022.1

バージョンが異なる場合、違う書き方になっているもの等が存在する場合がありますので、 公式ドキュメント等を参照し適宜読み替えていただければと思います。

目次

  1. はじめに
  2. インストールマニフェストとは
  3. インストールマニフェストのメリット・デメリット
  4. インストールマニフェストの始め方と基本構造
    1. マニフェストの作成
    2. マニフェストの編集
    3. マニフェストの実行
  5. インストールマニフェストでできること
    1. 変数の設定
    2. ネームスペースとデータベースの設定
    3. データのインポートとマッピング
    4. セキュリティ設定
    5. InterOperability 機能の設定
  6. インストールマニフェスト以外で行う環境設定
    1. ObjectScriptによる実装
    2. Pythonによる実装
  7. まとめ

1. はじめに

IRISを使用するにあたって、管理ポータルでの環境設定は切っても切れない作業だと思います。 IRIS のインストールマニフェストを使用することで、ネームスペース、データベース、セキュリティ設定、InterOperabilityの有効化、 さらにはカスタムコードの実行まで、一連のプロセスを自動化することができます。

本記事では、実際のマニフェストファイルを例に挙げながら、IRIS の環境設定自動化の方法について解説します。

なお、本記事で解説しているサンプルコードの全文と、付随するフォルダ・ファイルについては、Githubにて公開しています。

2. インストールマニフェストとは

IRIS のインストールマニフェストとは、%Installerというツールのことを指します。 インストールマニフェスト定義を記述するだけで、 IRIS環境設定を変更するために必要なコードを自動生成することができます。 他人に共有する際は、定義したインストールマニフェストを配布するだけで済みます。

インストールマニフェストは XML 形式で記述されます。 主要な要素として <Manifest><Namespace><Configuration><Database> などがあります。

なお、公式ドキュメントは以下です。

インストール・マニフェストの作成および使用

3.インストールマニフェストのメリット・デメリット

私が使ってみて感じた、インストールマニフェストのメリット・デメリットについてお伝えします。 全ての場合でインストールマニフェストが優れているとは言えないと思いますので、下記を参考に使用したほうが良いかどうか判断してもらえたらと思います。

  • メリット

    • IRIS環境構築(管理ポータルで手動で実行していた作業)の自動化ができる
    • 環境構築内容をコードとして管理できる
    • 共通の環境を誰でも簡単に、素早く作れるようになる
    • 事前に内容を定義しておけるので、管理ポータルで操作してうっかり設定ミスや設定忘れをしてしまうといったことがなくなる
  • デメリット

    • 環境構築経験が豊富でない人にとっては、公式ドキュメントを読みながらでもコードが示す内容の把握が難解なところがある
    • マニフェストの記法を理解した人でないと、コードのメンテナンスを実施できない
    • 定義の作成、定義の配布、実行方法の共有など、事前準備に手間がかかるため、少人数の環境が対象だったり、設定項目が少なかったりすると手間のほうが大きくなる可能性がある

4. インストールマニフェストの始め方と基本構造

4-1. マニフェストの作成

インストールマニフェストは、簡単に作成することができます。 例えばあなたがスタジオを使っている場合、下記の手順でテンプレートを作成できます。

ファイル > 新規作成 > 一般 > %Installer マニフェスト > OK

こうして作成されるマニフェストは、以下のようになっています。

Include %occInclude  

/// %Installer Manifest MyApp.MyInstaller
Class MyApp.MyInstaller
{  
  
/// マニフェスト定義.  
XData MyManifest [ XMLNamespace = INSTALLER ]  
{  
<Manifest>
	<Namespace>
		<Configuration>
			<Database>
				<!-- Your Manifest code here -->
			</Database>
		</Configuration>
	</Namespace>
</Manifest>
}  
  
/// これは XGL により生成されたメソッド・ジェネレーターです。.  
ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]  
{  
    #; XGL ドキュメントでこのメソッドのコードを生成する.  
    Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "MyManifest")  
}  
  
}

4-2. マニフェストの編集

なにやら見覚えのないコードがたくさん生成されますが、安心してください。 そのうち、私たちが編集すればよいのは基本的に下記の部分のみです。

<Manifest>
	<Namespace>
		<Configuration>
			<Database>
				<!-- Your Manifest code here -->
			</Database>
		</Configuration>
	</Namespace>
</Manifest>

■マニフェストの基本構造

詳細については後ほど解説しますが、ここでは基本的な構造について紹介していきます。

  • <Manifest>すべてのタグのルートタグである必要がある。 他のすべてのタグを含む。
  • <Namespace>ネームスペースを定義する。 【親タグ:<Manifest>
  • <Configuration><Namespace>内で構成タグの親タグとして記述する必要がある。【親タグ:<Namespace>
  • <Database>データベースを定義する。 【親タグ:<Configuration>

ここで覚えるべきは、<Manifest>タグは唯一無二ですべてのルートタグとなること、 その中身となるそれぞれのタグにも親子関係があるためそれを守らなければならないこと、の2点です。

これら以外の記述は、インストールマニフェストの作成や実行に必要なコードです。 詳細の説明については、下記のページにあるので任せたいと思います。

%InstallerでInterSystems Cachéにアプリケーションをデプロイする

4-3. マニフェストの実行

このマニフェストを実行したいときは、ターミナルで以下のコマンドを実行してください。 ※マニフェストを実行する時は、%SYSネームスペースで実行することを推奨します。(それ以外のネームスペースでも動作はします)

USER>zn "%SYS"
%SYS>do ##class(MyApp.MyInstaller).setup()

そうすると、マニフェストが環境設定のためのコードを生成し、そのコードが実際にIRISの環境設定を変更していきます。

5. インストールマニフェストでできること

それではさっそく、インストールマニフェストで実際にできることについてみていきましょう。 私が触ったことのある機能を中心に紹介していますが、前述の公式ドキュメントにはそれ以外の設定もできるXMLタグが多数紹介されていますので、参照してみてください。

5-1. 変数の設定

マニフェストでは、変数を設定することができます。 変数設定ができるタグには2種類あります。

  • <Default>:変数値がまだ設定されていない場合のみ、変数値を設定します。(すでに値が設定されている場合、無効になる)【親タグ:<Manifest>
  • <Var>:マニフェストで使用できる変数を定義および設定します。【親タグ:<Manifest>
<Var Name="var1" Value="aaa" />
// 事前に変数 var1 が設定されているので、var1 は aaa のまま
<Default Name="var1" Value="bbb" />
// 事前に変数 var2 は設定されていないので、var2 は ccc になる
<Default Name="var2" Value="ccc" />

5-2. ネームスペースとデータベースの設定

マニフェストを使用して、ネームスペースとそれに関連するデータベースを簡単に作成できます。 関連するタグは3種類です。

  • <Namespace>:ネームスペースを定義する。【親タグ:<Manifest>
    • Name:ネームスペースの名前
    • Create:新しいネームスペースを作成するかどうか(yes/no/overwrite) ※デフォルト:yes
    • Code:コード用データベースの指定
    • Data:データ用データベースの指定
    • Ensemble:InterOperabilityを使用するネームスペースかどうかの指定
  • <Configuration><Namespace> 内で構成タグの親タグとして記述する必要がある。【親タグ:<Namespace>
  • <Database>:データベースを定義する。【親タグ:<Configuration>
    • Name:データベース名
    • Dir:データベース・ディレクトリ
    • Create:新しいデータベースを作成するかどうか
    • InitialSize:データベースの初期サイズ(MB)
    • Resource:データベースへのアクセスを制御するリソース
    • PublicPermissions:リソースに割り当てられる許可の値(新規作成リソースのみ適用)(R/W/RW)
<Default Name="Namespace" Value="TESTNMSP"/>  
<Default Name="DATADB" Value="${Namespace}-GBL"/>  
<Default Name="CODEDB" Value="${Namespace}-RTN"/>
<Default Name="SetupDir" Value="C:\work\git"/>

<!-- ネームスペース作成 -->  
<Namespace Name="${Namespace}" Code="${CODEDB}" Data="${DATADB}" Create="yes" Ensemble="0">  
	<!-- DB作成 -->  
	<Configuration>  
		<Database Name="${DATADB}" Dir="C:\IRISDB\${Namespace}\GBL" Create="yes" InitialSize="100" Resource="%DB_${DATADB}" PublicPermissions="R"/>  
		<Database Name="${CODEDB}" Dir="C:\IRISDB\${Namespace}\RTN" Create="yes" InitialSize="10" Resource="%DB_${CODEDB}" PublicPermissions="R"/>  
	</Configuration>  
</Namespace>

■結果(管理ポータル画面)

(ネームスペース)

(データベース)

5-3. データのインポートとマッピング

マニフェストを使用して、特定のネームスペースに既存のデータやコードをインポートすることもできます。 関連するタグは1種類です。(既出除く)

  • <Import>:ファイルをインポートする。(%SYSTEM.OBJ.ImportDir または %SYSTEM.OBJ.Load を使用する)【親タグ:<Namespace>
    • File:インポートするファイルまたはフォルダ
    • Flags:コンパイル・フラグ(参考:フラグおよび修飾子
    • Recurse:再帰的にインポートするかどうかを指定 ※デフォルト:0
    • IgnoreErrors:エラー時に続行するかどうかを指定 ※デフォルト:0
<Default Name="Namespace" Value="TESTNMSP"/>  
<Default Name="DATADB" Value="${Namespace}-GBL"/>  
<Default Name="CODEDB" Value="${Namespace}-RTN"/>
<Default Name="SetupDir" Value="C:\work\git"/>

<Namespace Name="${Namespace}" Code="${CODEDB}" Data="${DATADB}" Create="yes" Ensemble="0">  
	<!-- グローバル、クラス、ルーチンインポート -->  
	<Import File="${SetupDir}\Test1" Flags="ck" Recurse="1" IgnoreErrors="1"/>  
	<Import File="${SetupDir}\Test2" Flags="ck" Recurse="1" IgnoreErrors="1"/>  
</Namespace>

■結果(管理ポータル画面)

マニフェストを使用して、グローバルやクラスをマッピングすることもできます。 関連するタグは3種類です。(既出除く)

  • <GlobalMapping>:グローバルを現在のネームスペースにマッピングする。【親タグ:<Configuration>
    • Global:グローバル名
    • From:グローバルのソース・ネームスペース
  • <ClassMapping>:パッケージを現在のネームスペースにマッピングする。【親タグ:<Configuration>
    • Package:マップするパッケージ
    • From:マッピングに使用するソース・データベース
  • <RoutineMapping>:ルーチンを現在のネームスペースにマッピングする。【親タグ:<Configuration>
    • Name :ルーチン
    • Type :ルーチン・タイプ
    • From:ルーチンのソース・データベース
<Default Name="Namespace" Value="TESTNMSP"/>
<Default Name="Namespace2" Value="${Namespace}2"/>  
<Default Name="DATADB2" Value="${Namespace2}-GBL"/>  
<Default Name="CODEDB2" Value="${Namespace2}-RTN"/>

<Namespace Name="${Namespace2}" Code="${CODEDB2}" Data="${DATADB2}" Create="yes" Ensemble="0">  
	<Configuration>
		<!-- DB作成 -->  
		<Database Name="${DATADB2}" Dir="C:\IRISDB\${Namespace2}\GBL" Create="yes" InitialSize="100" Resource="%DB_${DATADB2}" PublicPermissions="R"/>  
		<Database Name="${CODEDB2}" Dir="C:\IRISDB\${Namespace2}\RTN" Create="yes" InitialSize="10" Resource="%DB_${CODEDB2}" PublicPermissions="R"/>  
		<!-- グローバル、クラス、ルーチンマッピング設定 -->  
		<GlobalMapping Global="test2" From="${DATADB}"/>  
		<ClassMapping Package="Test2" From="${CODEDB}"/>  
	</Configuration>  
</Namespace>

■結果(管理ポータル画面)

5-4. セキュリティ設定

マニフェストを使用して、ロールやユーザアカウントを複数作成することができます。 関連するタグは2種類です。

  • <Role>:ロールを定義する。【親タグ:<Manifest>
    • Name:ロール名
    • Description:ロールの説明(カンマ不可)
    • Resources:ロールで保持されているリソースと特権。
    • RolesGranted:付与されるロール
  • <User>:ユーザを定義する。【親タグ:<Manifest>
    • Username:ユーザ名
    • PasswordVar:ユーザ・パスワードが含まれる変数の名前(変数名を渡す必要があることに注意)
    • Fullname:ユーザのフルネーム
    • Roles:ユーザを割り当てるロールのリスト
    • Namespace:ユーザの実行開始ネームスペース
    • Enabled:ユーザが有効かどうか
    • Comment:オプションコメント
    • ChangePassword:次回ログイン時にユーザにパスワードの変更を要求するかどうか
    • ExpirationDate:それ以降のユーザ・ログインが無効になる日付
<Default Name="TestUserPw" Value="12345"/>

	<!-- ロール作成・変更 -->  
<Role  
	Name="TestOperator"  
	Description="テスト運用者ロール"  
	Resources="%DB_TESTNMSP-GBL:RW,%DB_TESTNMSP-RTN:RW"  
	RolesGranted="%Developer"/>  
<Role  
	Name="TestAdministrator"  
	Description="テスト管理者ロール"  
	RolesGranted="%All"/>  
 
<!-- ユーザ作成・変更 -->  
<User  
	Username="TestUser1"  
	PasswordVar="TestUserPw"  
	Fullname="テストユーザ1"  
	Roles="TestOperator"  
	Namespace="USER"  
	Enabled="1"  
	Comment="テストユーザ1"/>  
<User  
	Username="TestUser2"  
	PasswordVar="TestUserPw"  
	Fullname="テストユーザ2"  
	Roles="TestAdministrator"  
	Namespace="USER"  
	Enabled="1"  
	Comment="テストユーザ2"/> 

■結果(管理ポータル画面)

(ロール)

(ユーザ)

■クラスメソッドの実行(Invoke)

また、管理ポータルのセキュリティ設定をまるっと読み込むこともできます。 これにより、管理ポータルやターミナル等のログインの有効化や、詳細のセキュリティ設定までを一括で行うことができます。 ロールやユーザアカウントについても、この読み込みにより一括で作成することができます。 関連するタグは2種類です。(既出除く)

  • <Invoke>:クラス・メソッドを呼び出して、実行結果を変数の値として返す。【親タグ:<Namespace>
    • Class:クラス名
    • Method:メソッド名
    • CheckStatus:返されたステータスをチェックするかどうか
    • Return:結果の書き込み先の変数の名前
  • <Arg><Invoke> または <Error> から呼び出されるメソッドに引数を渡す。【親タグ:<Invoke>, <Error>
    • Value:引数の値
<Default Name="SetupDir" Value="C:\work\git"/>

<Namespace Name="%SYS" Create="overwrite">  
	<!-- セキュリティ設定のインポート -->  
	<Invoke Class="Security.System" Method="ImportAll" CheckStatus="false">  
		<Arg Value="${SetupDir}\SecurityExport.xml"/>  
	</Invoke>  
</Namespace>

これらのタグは、セキュリティ設定のインポート以外にも様々な用途に使用することができます。 例えば、タスクスケジュール全体のインポートをセキュリティと同じように行ったり、自作のクラスの処理を実行したり、既存のシステムクラスの処理を実行したりなどです。

※管理ポータルのログインの有効化設定については、2024.3以降のバージョンであればマニフェストのタグにて変更することができます。 (ターミナルのログイン有効化については、現在は<Invoke>を用いる方法か、後述の別途マニフェスト以外のコードを書く方法で実現するしかありません) 具体的には、下記のタグで実現できます。

  • <CSPApplication>:クラス内で定義されている 1 つ以上の Web アプリケーションを定義する。【親タグ:<Namespace>
    • AuthenticationMethods:有効な認証方法(例:32=password、64=unauthenticated)
    • CSPEnabled:CSP が有効かどうか ※デフォルト:1
    • DefaultTimeout:セッション・タイムアウト
    • Description:説明
    • Directory:CSP ファイルへのパス
    • Url:Webアプリケーションの名前

※セキュリティ設定のインポートの事前準備として、管理ポータルのセキュリティ設定(上述の「SecurityExport.xml」にあたるもの)をXMLとしてエクスポートしておく必要があります。 エクスポートは、次のように実施します。 ターミナルで^SECURITY ユーティリティを起動し、12) System parameter setup > 5) Export All Security settings を選択します。 そうすると、C:\InterSystems\[IRISインスタンス名]\mgr\SecurityExport.xml ができているはずです。 (IRISを入れている場所によっては出力場所は異なります)

★4.セキュリティ情報(ユーザ・サービスなど)のインポートInterSystems 製品の設定内容をインポート/エクスポートする方法 > セキュリティについて

%SYS>Do ^SECURITY
:
Option? 12       // System parameter setup
:
Option? 5        // Export All Security settings

Export ALL security records? Yes => Yes

Export to file name SecurityExport.xml =>
Parameters? "WNS" =>
Confirm export of selected security records to SecurityExport.xml? No => Yes

■結果(管理ポータル画面)

(デフォルトでは管理ポータルのログイン時にパスワード認証はないが、それをマニフェストで有効化した例)

5-5. InterOperability 機能の設定

InterOperability機能を使用する場合、専用のネームスペースを作成することができます。 また、プロダクションを自動的に設定することもできます。 関連するタグは2種類です。<Namespace>も改めて紹介します。

  • <Namespace>:ネームスペースを定義する。【親タグ:<Manifest>
    • Name:ネームスペースの名前
    • Create:新しいネームスペースを作成するかどうか(yes/no/overwrite) ※デフォルト:yes
    • Code:コード用データベースの指定
    • Data:データ用データベースの指定
    • Ensemble:InterOperabilityを使用するネームスペースかどうかの指定
  • <Production>:プロダクションを定義する。【親タグ:<Namespace>
    • Name:プロダクション名
    • AutoStart:プロダクションを自動的に起動するかどうか ※デフォルト:0
<Default Name="Namespace3" Value="ENSNMSP"/>
<Default Name="DATADB3" Value="${Namespace3}-GBL"/>  
<Default Name="CODEDB3" Value="${Namespace3}-RTN"/>  
<Default Name="SetupDir" Value="C:\work\git"/>

<Namespace  Name="${Namespace3}"  Code="${CODEDB3}"  Data="${DATADB3}"  Create="yes"  Ensemble="1">
	<!-- Database作成などの設定は省略 -->
	<!-- グローバル、クラス、ルーチンインポート -->  
	<Import File="C:\work\git\Test3" Flags="ck" Recurse="1" IgnoreErrors="1"/>
	<!-- プロダクションの作成 -->
	<Production  Name="Test3.job.Main"  AutoStart="1"  />
</Namespace>

■結果(管理ポータル画面)

6. インストールマニフェスト以外で行う環境設定

マニフェストを作成していると、管理ポータルでは設定できるけどマニフェストではどうやるのだろう?という設定に度々出会います。 公式ドキュメントを見るなどしてマニフェストでの実現方法がわかる場合もありますが、 中にはマニフェストでは実現方法がないもの、後続のバージョンでは修正されたが今使っているバージョンではバグが残っており実現できないもの、 等がある場合があります。

その場合、あきらめて管理ポータルで設定するというのも手ですが、 別途コード化してマニフェストの処理と一緒に実施してしまうのもありです。

実際に、いくつかの設定をマニフェスト以外のコードで実現し、それをマニフェストと一緒に実行するコードの簡単な例をご紹介します。

6-1. ObjectScriptによる実装

下記のコードでは、マニフェストの生成・実行処理であるsetupメソッド(前述のスタジオでの新規作成にて自動作成されるメソッド)を、 自作のsetupExecuteというメソッドでラップしています。 その上で、ロケールの変更や不要タスクの一時停止といった処理をコードで記述し、実行します。

/// <h2>マニフェスト生成・実行処理</h2>  
/// <p><pre>SAMPLES>  
/// Do ##class(MyApp.MyInstaller).setup()  
/// </p></pre>  
ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]  
{  
	#; XGL ドキュメントでこのメソッドのコードを生成する.  
	Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "MyManifest")  
}  
  
/// <h2>セットアップ開始処理</h2>  
/// <p>return %Status</p>  
/// <p><pre>SAMPLES>  
/// Do ##class(MyApp.MyInstaller).setupExecute()  
/// </p></pre>  
ClassMethod setupExecute(ByRef pVars) As %Status  
{  
	Set tSC = 0  
	New $NAMESPACE  
	Set $NAMESPACE = "%SYS"  
	#; すでにネームスペースがあるときはManifestの処理はスキップ  
	If ('##class(%SYS.Namespace).Exists("TESTNMSP")) {  
		Set tSC = ..setup(.pVars)  
	}  
	  
	#; 日本語ロケールへ変更  
	Do ##class(Config.NLS.Locales).Install("jpuw")  
	#; 不要なタスクを停止  
	Do ..SuspendTask()  
	  
	Return tSC  
}

/// <h2>タスク停止</h2>  
/// <p>不要なタスクスケジュールを停止する。</p>  
/// <p><pre>SAMPLES>  
/// Do ##class(MyApp.MyInstaller).SuspendTask()  
/// </p></pre>  
ClassMethod SuspendTask()  
{  
	Set targetId = -1  
	Set query = 0  
	Set query($INCREMENT(query)) = "SELECT %ID,Name FROM %SYS.Task"  
	Set tStatement = ##class(%SQL.Statement).%New()  
	Do tStatement.%Prepare(.query)  
	Set result = tStatement.%Execute()  
	While (result.%Next()) {  
		If (result.%GetData(2) = "機能トラッカー") {  
			Set targetId = result.%GetData(1)  
			Quit  
		}  
	}  
	If (targetId '= -1) {  
		#; 機能トラッカーを一時停止  
		Do ##class("%SYS.TaskSuper").Suspend(targetId)  
	}  
}

これを実行する時は、setupメソッドではなくsetupExecuteメソッドを、ターミナルから実行します。 %SYSネームスペースから実行してください。

USER>ZN "%SYS"
%SYS>Do ##class(MyApp.MyInstaller).setupExecute()

■結果(管理ポータル画面)

(機能トラッカーを一時停止した結果)

6-2. Pythonによる実装

本題からは逸れてしまいますが、「InterSystems Embedded Python」について私は今まで触ったことがなかったため、この機会にチャレンジしてみました。 簡単にですが、その結果と所感について述べたいと思います。

6-1の内容を、Embedded Pythonを用いて書き換えたコードは以下です。 ※setupメソッドについては「objectgeneratorメソッド」という特別なメソッドのため、ObjectScriptのみでしか動作しません。そのため、Pythonへの書き換えはできないようでした。

/// <h2>マニフェスト生成・実行処理</h2>
/// <p><pre>SAMPLES>
/// Do ##class(MyApp.MyInstaller).setup()
/// </p></pre>
ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]
{
     #; XGL ドキュメントでこのメソッドのコードを生成する.
     Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "MyManifest")
}

/// <h2>セットアップ開始処理</h2>
/// <p>return %Status</p>
/// <p><pre>SAMPLES>
/// Do ##class(MyApp.MyInstaller).setupExecute()
/// </p></pre>
ClassMethod setupExecute(pVars As %SYS.Python = "") As %Status [ Language = python ]
{
	import iris
	tSC = 0
	# すでにネームスペースがあるときはManifestの処理はスキップ
	if not iris.cls('%SYS.Namespace').Exists('TESTNMSP') == 1:
		tSC = iris.cls(__name__).setup(pVars)

	# 日本語ロケールへ変更
	iris.cls('Config.NLS.Locales').Install('jpuw')
	# 不要なタスクを停止
	iris.cls(__name__).SuspendTask()

	return tSC
}

/// <h2>タスク停止</h2>
/// <p>不要なタスクスケジュールを停止する。</p>
/// <p><pre>SAMPLES>
/// Do ##class(MyApp.MyInstaller).SuspendTask()
/// </p></pre>
ClassMethod SuspendTask() [ Language = python ]
{
	import iris
	
	targetId = -1
	df = iris.sql.exec('SELECT %ID,Name FROM %SYS.Task').dataframe()
	for i in range(len(df)):
		if df.iloc[i, 1] == '機能トラッカー':
			targetId = df.iloc[i, 0]
			break

	if not targetId == -1:
    	# 機能トラッカーを一時停止
		iris.cls('%SYS.TaskSuper').Suspend(int(targetId))
}

※SuspendTaskメソッドの実行に当たっては、事前にpandasライブラリのインストールが必要です。 未インストールの場合、下記のコマンドを実行してインストールを実行してください。 (IRISを入れている場所によっては対象のパスは異なります)

> cd C:\InterSystems\[IRISインスタンス名]\bin
> irispip install --target ..\mgr\python pandas

Embededd Pythonを少しだけ使用してみた所感としては、 純粋にPythonを書くところは知っている記法をそのまま書けるので苦なく書けましたが、 IRISとの連携部分(IRISのクラスを利用するなどIRIS独自の機能を利用したいとき)は都度書き方を調べる必要があったので少し大変でした。 一度書き方を覚えてしまえばより多くのコードを書く時でも問題なさそうですが、慣れが必要だと思います。 ObjectScriptの記法に慣れていると、ObjectScriptで当たり前にできることがPythonでは実装が難しい、直感的に書けない場合もあるようなので、注意が必要です。

しかし、それを踏まえてもコードをPythonで書けるのは良いと思いました! Pythonの記法のメリットとしてObjectScriptよりもシンプルに記載できる箇所も多いですし、 前述のPythonでは実装が難しい部分についても、バージョンがあがっていくことで機能は徐々に追加されていくと思いますので、これからに期待ができます。 なにより、ObjectScriptの経験がない人に対しても共通の言語を持てるというのはとても素晴らしいことだと思います。

これを実行する時は、ObjectScriptのときと同じで問題ありません。 %SYSネームスペースから実行してください。 ※そうでないと、「Config.NLS.Locales」の実行時にエラーとなります(%SYSにあるパッケージのため)

USER>ZN "%SYS"
%SYS>Do ##class(MyApp.MyInstaller).setupExecute()

7. まとめ

IRIS のインストールマニフェストを使用することで、環境設定の自動化が可能になり、共通の環境を素早く構築できます。 これにより、開発チームの生産性が向上し、人為的なミスも減らすことができそうです。

本記事で興味を持っていただいた方は、ぜひインストールマニフェストを使ってみてください! 以上、ここまでお読みいただきありがとうございました。

0
1 309