#相互運用性

0 フォロワー · 90 投稿

ヘルスケアでは、相互運用性とは、さまざまな情報技術システムとソフトウェアアプリケーションが通信し、データを交換し、交換された情報を使用する能力です。

記事 Mihoko Iijima · 10月 16, 2025 1m read

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

この記事では、Developer Hub にまたまた新チュートリアル:InterSystems IRIS for Health:デジタルヘルスの相互運用性 が追加されましたので、体験内容についてご紹介します。(準備不要でブラウザがあれば試せるチュートリアルです!)

チュートリアルでは、InterSystems IRIS for Health を使用しているのですが、IRIS for Health の持つ機能により以下のような相互運用性シナリオを作成できます。

  • HL7、CDA、FHIR、DICOM のデータルーティングを管理
  • HL7 から FHIR への変換、CDA から HL7 への変換、FHIR から CDA への変換
  • 異なるシステムと API との間のデータフローを確立

チュートリアルの中では、あるシステムから入力される HL7 メッセージを他のシステムに送信する流れをご体験いただけます。

また、データ変換が必要な場合の対応方法や HL7 メッセージの一部をテーブルに保存する流れなどもご体験いただけます。

例)HL7 メッセージの一部をテーブルに格納

アカウント作成やログインも不要で  ボタンをクリックするだけで始められます👍

ぜひ、お試しください!​​​​​​

0
0 20
InterSystems公式 Seisuke Nakahashi · 5月 22, 2025

インターシステムズは、InterSystems IRIS、InterSystems IRIS for Health、HealthShare Health Connect のポイントリリース 2025.1 をリリースしました。
新しいバージョン番号は 2025.1.0.225.1 となります。
本リリースは、SDS対応ビジネスホストを利用するユーザに影響を与える、深刻な相互運用性の問題に対応するために行われました。

0
0 44
お知らせ Mihoko Iijima · 5月 7, 2025

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

次のコンテストの詳細が発表されましたのでご案内します。

🏆 InterSystems FHIR とデジタルヘルスの相互運用性コンテスト 2025 🏆

期間:2025年5月12日~6月1日

賞金総額:$12,000


0
0 37
記事 Toshihiko Minamoto · 3月 27, 2025 8m read

fastapi_logo

説明

これは、ネイティブウェブアプリケーションとして IRIS にデプロイできる FastAPI アプリケーションのテンプレートです。

インストール

  1. リポジトリをクローンする
  2. 仮想環境を作成する
  3. 要件をインストールする
  4. docker-compose ファイルを実行する
git clone
cd iris-fastapi-template
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
docker-compose up

使用法

ベース URL は http://localhost:53795/fastapi/ です。

エンドポイント

  • /iris - IRISAPP ネームスペースに存在する上位 10 個のクラスを持つ JSON オブジェクトを返します。
  • /interop - IRIS の相互運用性フレームワークをテストするための ping エンドポイント。
  • /posts - Post オブジェクトの単純な CRUD エンドポイント。
  • /comments - Comment オブジェクトの単純な CRUD エンドポイント。

このテンプレートからの開発方法

WSGI 導入記事をご覧ください: wsgiサポートの概要

概要: セキュリティポータルで DEBUG フラグをトグルすると、開発作業の過程で変更内容がアプリケーションに反映されるようになります。

コードの説明

app.py

これは FastAPI アプリケーションのメインのファイルです。 FastAPI アプリケーションとルートが含まれます。

from fastapi import FastAPI, Request

import iris

from grongier.pex import Director

# import models
from models import Post, Comment, init_db
from sqlmodel import Session,select

app = FastAPI()

# create a database engine
url = "iris+emb://IRISAPP"
engine = init_db(url)
  • from fastapi import FastAPI, Request - FastAPI クラスト Request クラスをインポートします。
  • import iris - IRIS モジュールをインポートします。
  • from grongier.pex import Director: Flask アプリを IRIS 相互運用性フレームワークにバインドする Director クラスをインポートします。
  • from models import Post, Comment, init_db - モデルと init_db 関数をインポートします。
  • from sqlmodel import Session,select - Session クラスと sqlmodel モジュールの選択された関数をインポートします。
  • app = FastAPI() - FastAPI アプリケーションを作成します。
  • url = "iris+emb://IRISAPP" - IRIS ネームスペースの URL を定義します。
  • engine = init_db(url) - sqlmodel ORM のデータベースエンジンを作成します。

models.py

このファイルには、アプリケーションのモデルが含まれます。

from sqlmodel import Field, SQLModel, Relationship, create_engine

class Comment(SQLModel, table=True):
    id: int = Field(default=None, primary_key=True)
    post_id: int = Field(foreign_key="post.id")
    content: str
    post: "Post" = Relationship(back_populates="comments")

class Post(SQLModel, table=True):
    id: int = Field(default=None, primary_key=True)
    title: str
    content: str
    comments: list["Comment"] = Relationship(back_populates="post")

説明することは特にありません。外部キーとリレーションによる単なるモデルの定義です。

init_db 関数は、データベースエンジンの作成に使用されます。

def init_db(url):

    engine = create_engine(url)

    # create the tables
    SQLModel.metadata.drop_all(engine)
    SQLModel.metadata.create_all(engine)

    # initialize database with fake data
    from sqlmodel import Session

    with Session(engine) as session:
        # Create fake data
        post1 = Post(title='Post The First', content='Content for the first post')
        ...
        session.add(post1)
        ...
        session.commit()

    return engine
  • engine = create_engine(url) - データベースエンジンを作成します。
  • SQLModel.metadata.drop_all(engine) - すべてのテーブルをドロップします。
  • SQLModel.metadata.create_all(engine) - すべてのテーブルを作成します。
  • with Session(engine) as session: - データベースを操作するためのセッションを作成します。
  • post1 = Post(title='Post The First', content='Content for the first post') - Post オブジェクトを作成します。
  • session.add(post1) - Post オブジェクトをセッションに追加します。
  • session.commit() - 変更内容をデータベースにコミットします。
  • return engine - データベースエンジンを返します。

/iris エンドポイント

######################
# IRIS Query example #
######################

@app.get("/iris")
def iris_query():
    query = "SELECT top 10 * FROM %Dictionary.ClassDefinition"
    rs = iris.sql.exec(query)
    # Convert the result to a list of dictionaries
    result = []
    for row in rs:
        result.append(row)
    return result
  • @app.get("/iris") - /iris エンドポイントの GET ルートを定義します。
  • query = "SELECT top 10 * FROM %Dictionary.ClassDefinition" - IRIS ネームスペースで上位 10 個のクラスを取得するクエリを定義します。
  • rs = iris.sql.exec(query) - クエリを実行します。
  • result = [] - 結果を保存する空のリストを作成します。
  • for row in rs: - 結果セットを反復処理します。
  • result.append(row) - 結果リストを行にアペンドします。
  • return result - 結果リストを返します。

/interop エンドポイント

########################
# IRIS interop example #
########################
bs = Director.create_python_business_service('BS')

@app.get("/interop")
@app.post("/interop")
@app.put("/interop")
@app.delete("/interop")
def interop(request: Request):
    
    rsp = bs.on_process_input(request)

    return rsp

  • bs = Director.create_python_business_service('BS') - Python ビジネスサービスを作成します。
    • ビジネスサービスの複数のインスタンスを防止するために、ルート定義の外に作成する必要があります。
  • @app.get("/interop") - /interop エンドポイントの GET ルートを定義します。
  • @app.post("/interop") - /interop エンドポイントの POST ルートを定義します。
  • ...
  • def interop(request: Request): - ルートハンドラーを定義します。
  • rsp = bs.on_process_input(request) - ビジネスサービスの on_process_input メソッドを呼び出します。
  • return rsp - レスポンスを返します。

/posts エンドポイント

############################
# CRUD operations posts    #
############################

@app.get("/posts")
def get_posts():
    with Session(engine) as session:
        posts = session.exec(select(Post)).all()
        return posts
    
@app.get("/posts/{post_id}")
def get_post(post_id: int):
    with Session(engine) as session:
        post = session.get(Post, post_id)
        return post
    
@app.post("/posts")
def create_post(post: Post):
    with Session(engine) as session:
        session.add(post)
        session.commit()
        return post

このエンドポイントは、Post オブジェクトで CRUD 操作を実行するために使用されます。

説明することは特にありません。すべての投稿を取得し、ID で投稿を取得し、投稿を作成するためのルートの定義です。

すべては sqlmodel ORM を使って行われます。

/comments エンドポイント

############################
# CRUD operations comments #
############################


@app.get("/comments")
def get_comments():
    with Session(engine) as session:
        comments = session.exec(select(Comment)).all()
        return comments
    
@app.get("/comments/{comment_id}")
def get_comment(comment_id: int):
    with Session(engine) as session:
        comment = session.get(Comment, comment_id)
        return comment
    
@app.post("/comments")
def create_comment(comment: Comment):
    with Session(engine) as session:
        session.add(comment)
        session.commit()
        return comment

このエンドポイントは、Comment オブジェクトで CRUD 操作を実行するために使用されます。

説明することは特にありません。すべてのコメントを取得し、ID でコメントを取得し、コメントを作成するためのルートの定義です。

すべては sqlmodel ORM を使って行われます。

トラブルシューティング

スタンドアロンモードで FastAPI アプリケーションを実行する方法

以下のコマンドを使用して、いつでもスタンドアロンの Flask アプリケーションを実行できます。

python3 /irisdev/app/community/app.py

注: このコマンドを実行するには、コンテナー内にいる必要があります。

docker exec -it iris-fastapi-template-iris-1 bash

IRIS でアプリケーションを再起動する

DEBUG モードでアプリケーションに複数の呼び出しを行うと、変更はアプリケーションに反映されます。

IRIS 管理ポータルへのアクセス方法

http://localhost:53795/csp/sys/UtilHome.csp に移動すると、IRIS 管理ポータルにアクセスできます。

このテンプレートをローカルで実行する

これには、マシンに IRIS がインストールされている必要があります。

次に、IRISAPP というネームスペースを作成する必要があります。

要件をインストールします。

IoP のインストール:

#init iop
iop --init

# load production
iop -m /irisdev/app/community/interop/settings.py

# start production
iop --start Python.Production

セキュリティポータルでアプリケーションを構成します。

0
0 75
記事 Toshihiko Minamoto · 2月 27, 2025 7m read

Flask_logo

説明

これは、ネイティブウェブアプリケーションとして IRIS にデプロイできる Flask アプリケーションのテンプレートです。

インストール

  1. リポジトリをクローンする
  2. 仮想環境を作成する
  3. 要件をインストールする
  4. docker-compose ファイルを実行する
git clone
cd iris-flask-template
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
docker-compose up

使用法

ベース URL は http://localhost:53795/flask/ です。

エンドポイント

  • /iris - IRISAPP ネームスペースに存在する上位 10 個のクラスを持つ JSON オブジェクトを返します。
  • /interop - IRIS の相互運用性フレームワークをテストするための ping エンドポイント。
  • /posts - Post オブジェクトの単純な CRUD エンドポイント。
  • /comments - Comment オブジェクトの単純な CRUD エンドポイント。

このテンプレートからの開発方法

WSGI 導入記事をご覧ください: wsgi-introduction

概要: セキュリティポータルで DEBUG フラグをトグルすると、開発作業の過程で変更内容がアプリケーションに反映されるようになります。

コードの説明

app.py

これはアプリケーションのメインのファイルです。 Flask アプリケーションとエンドポイントが含まれます。

from flask import Flask, jsonify, request
from models import Comment, Post, init_db

from grongier.pex import Director

import iris

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'iris+emb://IRISAPP'

db = init_db(app)
  • from flask import Flask, jsonify, request: Flask ライブラリをインポートします。
  • from models import Comment, Post, init_db: モデルとデータベース初期化関数をインポートします。
  • from grongier.pex import Director: Flask アプリを IRIS 相互運用性フレームワークにバインドする Director クラスをインポートします。
  • import iris: IRIS ライブラリをインポートします。
  • app = Flask(__name__): Flask アプリケーションを作成します。
  • app.config['SQLALCHEMY_DATABASE_URI'] = 'iris+emb://IRISAPP': データベース URI を IRISAPP ネームスペースに設定します。
    • iris+emb URI スキームは、埋め込み接続として IRIS に接続するために使用されます(別の IRIS インスタンスの必要はありません)。
  • db = init_db(app): Flask アプリケーションでデータベースを初期化します。

models.py

このファイルには、アプリケーションの SQLAlchemy モデルが含まれます。

from dataclasses import dataclass
from typing import List
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

@dataclass
class Comment(db.Model):
    id:int = db.Column(db.Integer, primary_key=True)
    content:str = db.Column(db.Text)
    post_id:int = db.Column(db.Integer, db.ForeignKey('post.id'))

@dataclass
class Post(db.Model):
    __allow_unmapped__ = True
    id:int = db.Column(db.Integer, primary_key=True)
    title:str = db.Column(db.String(100))
    content:str = db.Column(db.Text)
    comments:List[Comment] = db.relationship('Comment', backref='post')

説明することは特にありません。モデルはデータクラスとして定義されており、db.Model クラスのサブクラスです。

__allow_unmapped__ 属性は、comments 属性を使用せずに Post オブジェクトを作成できるようにするために使用する必要があります。

dataclasses はオブジェクトを JSON にシリアル化するのに使用されます。

init_db 関数は、Flask アプリケーションでデータベースを初期化します。

def init_db(app):
    db.init_app(app)

    with app.app_context():
        db.drop_all()
        db.create_all()
        # Create fake data
        post1 = Post(title='Post The First', content='Content for the first post')
        ...
        db.session.add(post1)
        ...
        db.session.commit()
    return db
  • db.init_app(app): Flask アプリケーションでデータベースを初期化します。
  • with app.app_context(): アプリケーションのコンテキストを作成します。
  • db.drop_all(): データベースのすべてのテーブルをドロップします。
  • db.create_all(): データベースのすべてのテーブルを作成します。
  • アプリケーションの偽データを作成します。
  • データベースオブジェクトを返します。

/iris エンドポイント

######################
# IRIS クエリ例 #
######################

@app.route('/iris', methods=['GET'])
def iris_query():
    query = "SELECT top 10 * FROM %Dictionary.ClassDefinition"
    rs = iris.sql.exec(query)
    # Convert the result to a list of dictionaries
    result = []
    for row in rs:
        result.append(row)
    return jsonify(result)

このエンドポイントは、IRIS データベースでクエリを実行し、IRISAPP ネームスペースに存在する上位 10 個のクラスを返します。

/interop エンドポイント

########################
# IRIS interop example #
########################
bs = Director.create_python_business_service('BS')

@app.route('/interop', methods=['GET', 'POST', 'PUT', 'DELETE'])
def interop():
    
    rsp = bs.on_process_input(request)

    return jsonify(rsp)

このエンドポイントは、IRIS の相互運用性フレームワークをテストするために使用されます。 ビジネスサービスオブジェクトを作成し、それを Flask アプリケーションにバインドします。

注: bs オブジェクトは有効な状態を維持するために、リクエストの範囲外にある必要があります。

  • bs = Director.create_python_business_service('BS'): 'BS' というビジネスサービスオブジェクトを作成します。
  • rsp = bs.on_process_input(request): リクエストオブジェクトを引数としてビジネスサービスオブジェクトの on_process_input メソッドを呼び出します。

/posts エンドポイント

############################
# CRUD operations posts    #
############################

@app.route('/posts', methods=['GET'])
def get_posts():
    posts = Post.query.all()
    return jsonify(posts)

@app.route('/posts', methods=['POST'])
def create_post():
    data = request.get_json()
    post = Post(title=data['title'], content=data['content'])
    db.session.add(post)
    db.session.commit()
    return jsonify(post)

@app.route('/posts/<int:id>', methods=['GET'])
def get_post(id):
    ...

このエンドポイントは、Post オブジェクトで CRUD 操作を実行するために使用されます。

dataclasses モジュールにより、Post オブジェクトは簡単に JSON にシリアル化できます。

以下では、すべての投稿を取得する sqlalchemy の query メソッドと、新しい投稿を作成するための addcommit メソッドを使用しています。

/comments エンドポイント

############################
# CRUD operations comments #
############################

@app.route('/comments', methods=['GET'])
def get_comments():
    comments = Comment.query.all()
    return jsonify(comments)

@app.route('/comments', methods=['POST'])
def create_comment():
    data = request.get_json()
    comment = Comment(content=data['content'], post_id=data['post_id'])
    db.session.add(comment)
    db.session.commit()
    return jsonify(comment)

@app.route('/comments/<int:id>', methods=['GET'])
def get_comment(id):
    ...

このエンドポイントは、Comment オブジェクトで CRUD 操作を実行するために使用されます。

Comment オブジェクトは外部キーによって Post オブジェクトにリンクされます。

トラブルシューティング

スタンドアロンモードで Flask アプリケーションを実行する方法

以下のコマンドを使用して、いつでもスタンドアロンの Flask アプリケーションを実行できます。

python3 /irisdev/app/community/app.py

注: このコマンドを実行するには、コンテナー内にいる必要があります。

docker exec -it iris-flask-template-iris-1 bash

IRIS でアプリケーションを再起動する

DEBUG モードでアプリケーションに複数の呼び出しを行うと、変更はアプリケーションに反映されます。

IRIS 管理ポータルへのアクセス方法

http://localhost:53795/csp/sys/UtilHome.csp に移動すると、IRIS 管理ポータルにアクセスできます。

このテンプレートをローカルで実行する

これには、マシンに IRIS がインストールされている必要があります。

次に、IRISAPP というネームスペースを作成する必要があります。

要件をインストールします。

IoP のインストール:

#init iop
iop --init

# load production
iop -m /irisdev/app/community/interop/settings.py

# start production
iop --start Python.Production

セキュリティポータルでアプリケーションを構成します。

0
0 69
記事 Hiroshi Sato · 2月 12, 2025 1m read

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

インターオペラビリティ機能を使用してビジネスホストのビジネスロジックを実装する際に、デバッグ等の目的でログ出力を行うための専用マクロが用意されているので、ご紹介します。

以下のマクロが用意されています。

$$$LOGINFO("これはログです。")  
$$$LOGERROR("これはエラーです。")  
$$$LOGWARNING("これは警告です")
$$$LOGSTATUS(status) 
$$$LOGSTATUS(status2) 
$$$ASSERT("これはアサートです。")

ビジネスオペレーション等のコードに上記のコードを書くことにより、インターオペラビリティのイベントログにその内容が表示されます。

以下の様に表示されます。
 

0
0 67
記事 Mihoko Iijima · 1月 21, 2025 16m read

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

Teams ワークフロー Webhook を用意すると、curl コマンドや REST クライアントを利用して Teams チャネルに任意メッセージを簡単に送信できるので、IRIS や IRIS の Interoperability を使って自動的に何か情報を入手+必要なときだけ Teams チャネル通知ができたら面白いな、と思い試してみた内容をご紹介します。

以下、Teamsワークフローの作成例です。

Teams ワークフローの仕様に合わせたメッセージ用 JSON が用意できれば、こんなメッセージを出すことができます。

Teams チャネルにメッセージを通知するには「Teams ワークフローの Webhook」の用意が必要です。(この用意によってアクセスするために必要なURLが生成されます)詳しくは、「Microsoft Teamsのワークフローを使用して受信 Webhook を作成する」をご参照ください。

通知までの設定などについては、こちらのページを参考にさせていただきました:Teams チャネルへメッセージ送信する方法

以下、試した順でご紹介します。

1. curl コマンドでまずは実行してみる

2. シンプルにターミナルから試す

3. 通知メッセージのJSONを変えてみる

4. メッセージのJSONをJSONテンプレートエンジンで作ってみる

0
0 95
記事 Mihoko Iijima · 12月 24, 2024 3m read

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

イベントログの削除には、Ens.Util.LogクラスのPurge()メソッドを使用します。実行時以下の引数を指定します。

第1引数:削除数(参照渡し)

第2引数:保持日数(デフォルト7)

メッセージの削除には、2種類の方法があります。

1) 2022.1.2以降の導入されたマルチプロセスで削除する方法

Ens.Ens.Util.MessagePurgeクラスのPurge()メソッドを使用します。実行時以下の引数を指定します。

第1引数:削除数(参照渡し)

第2引数:保持日数(デフォルト7)

第3引数:1を指定(Completeではないメッセージの削除を防止するための指定)

第4引数:メッセージボディも一緒に削除する場合は1を指定

第5引数:デフォルトは500(秒)が設定されていますが、大量のメッセージをパージするとクリアされたビットマップの最適化に時間を要して最適化が完了しない場合があるため、大量削除の場合は 10000000000など大きな値を指定します。

2) Ens.MessageHeaderクラスのPurge()メソッドを使用する方法。

実行時以下の引数を指定します。

第1引数:削除数(参照渡し)

第2引数:保持日数(デフォルト7)

第3引数:1を指定(Completeではないメッセージの削除を防止するための指定)

0
0 55
記事 Mihoko Iijima · 12月 18, 2024 2m read

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

試していたWebAPIでは、POST要求時クエリパラメータとボディの両方を送る必要がありましたので、HTTPアウトバウンドアダプタが提供するメソッド:Post()/PostFormDataArray()/PostURL() 辺りをドキュメントで確認していたのですが、残念ながら両方を渡せるように作成された丁度良いメソッドがありませんでした。

ドキュメント:HTTPアウトバウンドアダプタが提供するメソッド

では、どのように送ったかというと、SendFormDataArray()の第3引数を利用して両方の情報を送付してみました。

具体的には、SendFormDataArray()の第2引数にはHTTPメソッド(GET、POST、PUT、DELETEなど)第3引数に%Net.HttpRequestのインスタンスが渡せる仕様になっていましたので、クエリパラメータとボディを%Net.HttpRequestのインスタンスに設定し、第3引数に指定して実行する方法をとりました。

set status=..Adapter.SendFormDataArray(.pHttpResponse,"POST",httprequest)
  if$$$ISERR(status) {
    return status
  }

変数httprequestの中身は以下のように作成しています

0
0 94
記事 Toshihiko Minamoto · 12月 10, 2024 9m read

コミュニティメンバーから、Python 2024 コンテストでの出品に対する非常に素晴らしいフィードバックが届きました。 ここで紹介させていただきます。

純粋な IRIS の 5 倍以上のサイズでコンテナーをビルドしているため、時間がかかっています

コンテナーの始動も時間はかかりますが、完了します

バックエンドは説明通りにアクセス可能です

プロダクションは稼動しています

フロントエンドは反応します

何を説明したいのかがよくわかりません

私以外のエキスパート向けに書かれた説明のようです

出品はこちら: https://openexchange.intersystems.com/package/IRIS-RAG-App

このようなフィードバックをいただけて、本当に感謝しています。プロジェクトに関する記事を書く素晴らしいきっかけとなりました。 このプロジェクトにはかなり包括的なドキュメントが含まれてはいますが、ベクトル埋め込み、RAG パイプライン、LLM テキスト生成のほか、Python や LLamaIndex などの人気の Python ライブラリに精通していることが前提です。

この記事は、IRIS での RAG ワークフローを実証するに当たって、上記の前提事項や、それらが IRIS で RAG ワークフローをこのプロジェクトにどのように適合するかについてを説明する試みです。AI をまったく使用せずに書かれています。

コンテナーが大きいのは、ベクトル埋め込みの作成に関わる Python パッケージに必要なライブラリ依存関係が非常に大きいためです。 より選択的にインポートすることで、サイズを大幅に縮小することが可能です。

コンテナーの初回ビルドには確かに時間がかかりますが、一度ビルドすれば起動時間は短くなります。 とはいえ、起動時間は確かに改善できるかもしれません。 起動にこれほどの時間がかかる主な理由は、アプリケーションのある個所が最後の起動から変更されていることを想定して entrypoint.sh が更新されているためです。これには、データベースの移行、CSS 構成、JavaScript 構成、Python バックエンドコードも含まれており、起動のたびにプロジェクト全体がリコンパイルされます。 これは、このプロジェクトを開発し始めやすくするためで、そうでない場合は、変更が適用されるたびに、フロントエンドとバックエンドのビルドを適切に実行するのが困難になってしまいます。 こうすることで、プロジェクトのコードを変更した場合はコンテナーを再起動し、場合によってはバックエンドのプロダクションを復旧すれば、アプリケーションのインターフェースと操作に変更が反映されます。

バックエンドのプロダクションは、HTTP リクエストを Django アプリケーションに渡すものであり、このパッケージの相互運用性にとって非常に重要であると確信しています。 ただし、私自身は IRIS プラットフォームの初心者であるため、プロダクションについてもっと学ぶ必要があります。

次に、ベクトル埋め込み、LLM、および RAG について、包括的に説明したいと思います。 この内最初に作られたのはベクトル埋め込みです。 まず、ベクトルについて説明します。 ほとんどのコンテキストにおいて、ベクトルは方向です。 空間のどこかを指す矢印です。 より正式には、ベクトルは「大きさだけでなく方向も持つ量」です。 これは、特定の方向へ移動し、空間内の特定の地点で爆発する花火によって例えることができます。 すべての花火が同じ中心点、つまり原点である [0,0,0] から発射され、その原点の周囲に雲となって飛び散るとします。 数学的には、3 つの座標系 [x,y,z] を使用して各花火の爆発の位置を表現することができ、これが花火の爆発の「ベクトル埋め込み」となります。 花火のビデオをたくさん撮影し、花火の爆発をすべてデータセットとして記録すると、花火の一種のベクトル埋め込みデータベース、つまりベクトルストアが作成されることになります。

花火に関する情報を使って何ができるでしょうか? 特定の花火を指して、花火全体の中から同じ点に最も近い位置で爆発した花火について尋ねると、空間の近くの点で爆発した他の花火を検索できます。 最もちかいものを見つけるだけですが、これを行うために数式があります。

花火ごとに、x、y、z の 3 つの数値のみを記録したことに注意してください。3 次元空間において、地上の花火発射台を [0,0,0] としています。

他の特定の花火に対して、距離と時間の両方の観点で最も近く爆発した花火も知りたい場合はどうでしょうか? それを知るには、花火の映像を確認して、各爆発の時間も記録しなければなりません。 これで、4 つの数値を持つ 4 次元ベクトルが取得されました。花火の爆発の 3 次元の位置に爆発の時間を加えたベクトルです。 ベクトル埋め込みにもう 1 つの次元を追加することで、花火の埋め込みがより記述的になりました。

これを機械学習に変換するとどうなるでしょうか? 手短に言えば、大量のテキストデータを処理することで、コンピューター科学者は、フレーズ、文章、段落、またはページなどのテキストを変換し、理論的な高次元空間の点を表現する非常に長い一連の数値に変換できる埋め込みモデルを作成することができました。

4 つの数字ではなく、300、700、さらには 1500 もの数字があります。 これらは、1 つのテキストが互いに「近い」か「遠い」かを 1500 通りまたは1500 次元の意味で表します。 テキストの意味を何らかの方法で表す数字を作成する手段があるというわけですから、多くの人にとって魅力的な概念と言えるでしょう。

数学を使用すると、これらの高次元テキストベクトル埋め込みのうち 2 つを比較して、同じモデルによって作成された場合に、それらが互いにどの程度類似しているか、つまり「近い」かを調べることができます。

このアプリで最初の行われているのが正にこれです。ユーザーはドキュメントを追加して名前を付け、埋め込みのタイプを選択する必要があります。 サーバーはそのドキュメントを受け取り、テキストのチャンクに分割してから、それぞれのチャンクをベクトル埋め込みに変換します。そのチャンクはそのドキュメントの専用のテーブルの行として保存されます。 各ドキュメントは、さまざまなテキスト埋め込みモデルによって作成されるベクトル埋め込みの可変長に対応できるように、それぞれの専用テーブルに保存されます。

ドキュメントがベクトル埋め込みとしてデータベースに保存されると、ユーザーはドキュメントに「尋ねる」クエリを入力できるようになります。 このクエリは 2 つの方法で使用されます。 1 つは、ドキュメントを検索するためです。 従来のテキスト検索は実行せずに、「ベクトル検索」を実行します。 アプリはクエリを受け取り、それをベクトル埋め込みに変換してから、クエリベクトル埋め込みに最も築地する埋め込みのあるドキュメントのセクションを検索します。 各ドキュメントセクションには 0 と 1 の間の類似性スコアが生成され、top_k_similarity と similarity_threshold に基づいて、ベクトルデータベースから複数のセクションが検索されます。 基本的に、取得するドキュメントのセクション数と取得の対象となるためにクエリとどの程度類似している必要があるかを指定することができます。

これが、検索拡張生成における取得です。 次は生成に移りましょう。

コンピューター科学者がテキストを意味的に重要な数値ベクトル埋め込みに変換する方法を見つけると、次に、テキストを生成するモデルの作成に移りました。 これは大きな成功を生み出し、現在では GPT-4、LLama3、Claude 3.5 などの大規模言語モデルとなっています。 これらの LLM はプロンプトまたはクエリを受け取り、補完または回答を提供します。これは LLM が提示されたテキストであるプロンプトから最も続行できる可能性があると考えるテキストです。

LLM は大量のテキストデータに対してトレーニングする必要があり、その回答または補完はそのトレーニングデータに制限されます。 トレーニングセットにないデータを含む可能性のある補完を LLM に提供させる場合、または補完を特定のナレッジセットに基づかせる場合は、1 つの方法として、プロンプトに追加のコンテキストデータを含めることができます。 基本的に、トレーニングされていない内容について LLM から回答を得たい場合、プロンプトに情報を提供する必要があるということです。

多くの人は、ChatGPT やローカルの LLama インストールが自分の個人文書に基づいて回答を提供してくれることを望む状況に陥っていました。 ドキュメント内でその情報を検索し、プロンプトに貼り付けて、質問を入力するだけの単純な操作であり、手作業で行っていました。 それ自体が検索拡張生成です。 RAG は、より正確または利便的な応答を得られるように、ユーザークエリに関連する情報を検索し、LLM にクエリを提供する操作を自動化したに過ぎません。

このアプリでは、ベクトル検索で取得したドキュメントセクションは、インターフェースでモデルとしてラベル付けされている選択された LLM にクエリとともに送信され、回答のコンテキストが提供されます。

このプロジェクト用に制作した動画の例では、シェイクスピアの 2 つの戯曲の全文を含むドキュメント「ハムレット」と「リア王」を使って、「この戯曲の悪役は誰ですか?」と尋ねています。 IRIS データベースには、ハムレットとリア王の 2 つのテーブルがすでに存在します。 各テーブルには、各戯曲のテキストをセクションに分割して作成されたベクトル埋め込みの行が入力されています。 これらの埋め込みは、一連の長い数値によって各ドキュメントセクションの多次元を表現しています。

サーバーは、「この戯曲の悪役は誰ですか」という質問を、リア王のベクトル埋め込みを生成した Text-to-Vector モデルを使用して数値ベクトルに変換し、リア王テーブル内でそれに最も類似するセクションを見つけます。 これらはおそらく悪役という語が言及されたセクションかもしれませんが、悪役が明示的に言及されていない場合でも、裏切り、裏切り、欺瞞などの他の悪役についても言及されている可能性があります。 こういったドキュメントのセクションは、クエリに追加され、合わせてプロンプトとして LLM に送信されます。LLM は提供されたドキュメントのセクションに基づいて質問に回答します。

これはドキュメントごとに個別に実行されるため、クエリの回答はクエリされているドキュメントに応じて異なります。 これにより頭字語が補完されます。ベクトル検索の力を使用して関連するコンテキスト情報を取得することで、LLM からの応答の生成を強化しているためです。

この記事をお読みいただきありがとうございました。このトピックについては今後の記事でも発展させたいと思います。 フィードバックをお待ちしています。

0
0 82
記事 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
記事 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
記事 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
記事 Kosaku Ikeda · 9月 23, 2024 6m read

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

突然ですが、皆さんはIRISの機能にある「ユニットテスト」は利用されているでしょうか。
筆者はまだ実装まで行えていませんが、各関数の品質保証を担保するため導入を検討している段階です。

現状、IRISのユニットテストには下記2点の対応すべき点があると考えています。

  1. テスト結果の可読性が低い(先日vscodeで拡張機能が出ていましたが、やはり見ずらいと感じました)
  2. ユニットテストを自動で実行する手段がない

特にテストが継続的に自動で実施されないと、ユニットテスト自体が次第に陳腐化し、実行されなくなり忘れ去られる恐れがあると考えます。
ただし、意味もなく定期的にテストを実行しても効果がありません。
そこで、Gitのpushのタイミングで行おうと考えました。

次にテスト環境です。
テスト環境の構築は、テスト自動化の観点からみるとCI/CDツール等を利用するのが一般的だと思います。
ただ今回は、テスト環境の構築を簡易にすませたいと考え、IRISの既存技術を組み合わせて構築しようと考えました。

そこで運用幅の広いInteroperabilityとユニットテストを組み合わせて、テストの自動化が可能か考察していきたいと思います。

【ユニットテスト全体概要】

【全体の流れ】

 ■ユーザの開発環境

  ①ユーザは改修したクラスをGitへpushする

 ■Git用のサーバ

0
0 210
記事 Yusuke Kojima · 9月 17, 2024 5m read

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

突然ですが、2024年6月25日に開発者向けセミナー「FHIR 新機能のご紹介~2024.1~」が開催されました。
ご視聴になられた方も多数いらっしゃると思います。
まだご視聴になられていない方は是非一度、ご覧になってみてください。
YouTubeリンク

さて、こちらのセミナーにおいてご紹介された、IRIS for Health 2024.1からの新機能「FHIR Object Model」を用いて、リポジトリタイプのInteroperability開発の具体的なサンプルを作成してみました。
自身の備忘のため、すぐ開発環境を構築できるよう、コンテナ環境かつGitHubの公開もしております。
利用方法は、GitHub内のREADMEを参照ください。
GitHubリンク

目次

  1. FHIR Object Modelとは?

  2. メリット・デメリットを深堀り

  3. GitHub公開ソースについて

  4. 所感

1. FHIR Object Modelとは?

0
0 193
お知らせ Toshihiko Minamoto · 9月 12, 2024

Git を使用してIRIS でソリューションを構築することは、素晴らしいことです! 単にローカルの git リポジトリにVSCodeを使用し、サーバーに変更をプッシュする... それは非常に簡単です。

でも、次の場合はどうでしょうか。

  • 共有リモート開発環境で他の開発者と共同作業を行い、同じファイルの同時編集を回避したい場合
  • BPL、DTL、ピボット、ダッシュボードなどにおいて管理ポータルに基づくエディターを使用しており、 作業に簡潔なソース管理を使用したい場合
  • 一部の作業においては引き続き Studio を使用しているかたまに VSCode から Studio に戻っているか、チームがまだ VSCode を完全に採用しておらず、一部のチームメンバーが Studio の使用を希望している場合
  • 同じネームスペースで同時に多数の独立したプロジェクト(InterSystems Package Manager を使って定義された複数のパッケージなど)に取り組んでおり、(多数の個別のプロジェクトではなく)1 つの isfs 編集ビューからすべてのプロジェクトの作業を行い、適切な git リポジトリで変更を自動的に追跡する場合
0
0 198
記事 Toshihiko Minamoto · 3月 28, 2024 12m read

ローコードへの挑戦

こんな状況を思い浮かべてください。「ウィジェットダイレクト」というウィジェットとウィジェットアクセサリーを販売する一流のネットショップで楽しく勤務しています。先日、上司から一部の顧客がウィジェット商品にあまり満足していないという残念な話を聞き、苦情を追跡するヘルプデスクアプリケーションが必要となりました。さらに面白いことに、上司はコードのフットプリントを最小限に抑えることを希望しており、InterSystems IRIS を使って 150 行未満のコードでアプリケーションを提供するという課題をあなたに与えました。これは実際に可能なのでしょうか?

免責事項: この記事は、非常に基本的なアプリケーションの構築を記すものであり、簡潔さを維持するために、セキュリティやエラー処理などの重要な部分は省略されています。このアプリケーションは参考としてのみ使用し、本番アプリケーションには使用しないようにしてください。この記事ではデータプラットフォームとして IRIS 2023.1 を使用していますが、それ以前のバージョンでは記載されているすべての機能が提供されているとは限りません。

ステップ 1 - データモデルの定義

クリーンなネームスペースを新規に定義することから始めましょう。CODE と DATA データベースを使用します。 すべてを 1 つのデータベースで賄うことはできますが、分割してデータのリフレッシュを実行できるようにすると便利です。

このヘルプデスクシステムには 3 つの基本クラスが必要です。スタッフアドバイザーユーザーアカウント(UserAccount) と顧客連絡先ユーザーアカウント(UserAccount)間のやり取りを文書化するアクション(Actions)を含められる Ticket オブジェクトです。

19 行のコードで完全なデータモデルができました!2 つのクラスはデータベースに保存できるように Persistent(永続)に設定し、%JSON.Adapter を継承しています。この継承によって、JSON フォーマットでのオブジェクトのインポートとエクスポートを非常に簡単に行うことができます。テストとして、最初のユーザーをターミナルにセットアップし、保存してから JSONExport が正しく動作することを確認します。

すべてうまくいったようです。上司から、スタッフと顧客のリストが含まれる csv ファイルを渡されました。これを解析して読み込むコードを書くことは可能ですが、簡単に行う方法はないものでしょうか?

ステップ 2 - データの読み込み

InterSystems IRIS には、CSV ファイルから簡単にデータを読み込み、ヘッダーの解析やフィールド名の変更のオプションも使用できる SQL のLOAD DATA ステートメントが備わっています。使い方も単純です。では、それを使用してユーザーテーブルを読み込んでみましょう。

ヘッダーラベルを使ってこのデータを抽出し、データベースに読み込みます。

1 つのコマンドで全 300 行のデータがインポートされました。この 4 行のコードを加えると、合計 23 行のコードが記述したことになります。これらのレコードが正しいことを、基本的な SQL の SELECT を使って素早く確認してみましょう。

最初のデータを得られました。では、フロントエンドを接続できる基本的な API を作成しましょう。この API は、JSON を送受信する REST サービスとして作成します。

ステップ 3 - REST API の作成

InterSystems IRIS には、%CSP.REST クラスの継承を通じてネイティブの RESTサポートが備わっています。そこで、REST.Dispatch クラスを作成して %CSP.REST を継承することにします。このクラスは、URL と動詞をメソッドにマッピングする XData UrlMap と、これらの URL から呼び出されるメソッドの 2 つのセクションで構成されます。

ここで作成する実用最低限のツールには、スタッフまたは顧客のユーザーリストの取得、発行された最近のチケットの取得、ID 番号による単一のチケットの取得、および新しいチケットの作成の 4 つの演算が必要です。ここで使用する動詞を定義してからメソッドを定義します。

GetUserList は、直接 JSON にデータを出力する基本的な埋め込み SQL カーソルです。その後で、ネイティブの JSON 機能を使ってこれを解析し、JSON 配列にプッシュして、レスポンス本文として送信することができます。URL から直接クエリにスタッフ変数を渡して、データのコンテキストを変更します。

TicketSummary はほぼ同じですが、クエリは TICKET テーブルにアクセスします。

TicketSummary は最もシンプルなサービスです。ID でオブジェクトを開き、組み込みの %JSONExport を出力に書き込みます。オブジェクトが読み込みに失敗する場合、エラーパケットを出力します。

最後に、UploadTicket は最も複雑なメソッドです。 リクエストオブジェクトからペイロードを読み取り、JSON に解析してから %JSONImport を使って Ticket の新しいインスタンスに適用します。また、入力を待つ代わりに現在の時間から OpenDate と OpenTime も設定します。正しく保存できたら、オブジェクトの JSON 表現を呼び出すか、読み込み失敗する場合はエラーを返します。

このサービスにより、さらに 60 行のコードが全体に追加されました。これで、このアプリケーションの合計コード行数は、89 行になりました。

次は、セキュリティ > アプリケーションに Web アプリケーションを作成する必要があります。これには REST タイプのアプリケーションに設定し、クラス名を今作成したディスパッチクラスとして設定する必要があります(このアプリケーションがコードとデータにアクセスできるように適切なセキュリティロールを付与する必要があることに注意してください)。保存すると、REST サービスを定義した URL から呼び出せるようになります。

UserList を呼び出して確認してみましょう。

これで、データを作成する準備ができました。REST クライアントを使用して、ペイロードをチケット作成サービスに送信してみましょう。Keyword、Description、Advisor、および Contact を提供すると、作成したチケットの JSON が OpenDate と TicketId と共に返されます。

これで実用最低限のツールが完成しました。任意のフロントエンドフォームビルダーを使用して、REST サービス経由でチケット情報を送受信できるようになりました。

ステップ 4 - 相互運用性の要件

たった 89 行のコードで基本的なチケット管理アプリケーションが完成しました。上司も絶対に驚いたのでは?確かにそうですが、上司から悪い知らせを受けました。要件を逃しているというのです。ウィジェットダイレクトにはフランス語圏での特別な契約があり、フランス語によるチケットはすべて初回レビューを行う Mme Bettie Francis(ベティー・フランシス)を通過しなければならないのです。幸いにも、Robert Luman の Python 自然言語サポートに関する優れた記事を読み、テキストサンプルを受け入れて言語を識別できる REST サービスを作成したことのある同僚がいました。InterSystems IRIS 相互運用性を使用してこのサービスを呼び出し、テキストがフランス語であればアドバイザーを自動的にフランシスさんに更新するようにすることはできるでしょうか?

まずは、リクエストを送受信できるように、メッセージクラスを作成することから始めましょう。チケット ID とサンプルテキストを格納するリクエストと、言語コードと説明を返すレスポンスが必要です。 それぞれ Ens.Request と Ens.Response を継承します。

さて、さらに 6 行が追加され、合計 95 行のコードとなりました。次に演算を作成する必要があります。同僚のサービスにリクエストを送信して回答を取得する演算です。Outbount Operation を Server と URL のプロパティで定義し、これらを SETTINGS パラメーターに含めてユーザー構成に公開します。こうすることで、サーバーのパスが変更した場合に簡単にリクエストを更新できます。HTTPRequest をセットアップするヘルパーメソッドを作成してから、それを使用してサービスを呼び出し、レスポンスを作成します。

27 行のコードが追加され 100 行を超え、合計 122 行となりました。次に、このクラスを Ensemble 本番環境内にセットアップする必要があります。相互運用性の本番構成に移動し、「演算」ヘッダーの下にある「追加」を押します。クラス名と表示名で演算をセットアップしましょう。

次に、それをクリックして設定を開き、サーバー名と URL を入力して演算を有効にします。

次に、チケット ID を取り、入力されたユーザーアカウント ID をアドバイザーに設定する 2 つ目の演算が必要です。メッセージと演算クラスが必要ですが、この場合レスポンスは返さず、演算はフィードバックなしでタスクを実行します。

さらに 12 行が追加され、合計 134 行になりました。言語サービスを追加した方法でこの演算を本番環境に追加しますが、この場合、構成を設定する必要はありません。

次に、サービスを呼び出し、レスポンスを評価し、オプションとしてフランス語アドバイザーの演算を呼び出すルーターが必要です。「相互運用性」>「ビルド」>「ビジネスプロセス」に移動し、ビジュアルルールビルダーを開きます。リクエストとレスポンスのコンテキストを設定してから、呼び出しの項目を追加します。作成したメッセージクラスに入力と出力を設定したら、リクエストビルダーを使って入力をマッピングします。「非同期」フラグのチェックがオフになっていることを確認してください。レスポンスを待ってから処理を進めるためです。

次に「If」項目を追加して、返される言語コードを評価します。「fr」であれば、FrenchAdvisor 演算を呼び出すようにします。

フランシスさんのユーザー ID は 11 であるため、AdvisorUpdate メッセージを FrenchAdvisor サービスに供給するように呼び出しオブジェクトを設定し、ビルダーを使って、TicketID と固定値 11 を Advisor パラメーターに渡します。

「プロセス」ヘッダーの下にある「追加」をクリックし、クラスを選択して表示名「FrenchRouter」を指定したら、本番にこれを追加します。

これでルーティングが設定されました。 後は、新しいチケットをスキャンして、ルーターでの処理に送信するサービスが必要です。SQL アダプターに従ってサービスクラスを定義します(さらに 8 行のコードが追加されます)。

次に、演算オブジェクトとプロセスオブジェクトと同じようにして、これを本番に追加します。SQL アダプターのセットアップが必要です。ODBC DSN を介してローカルデータベースへの接続情報を提供し、CallInterval 設定に設定されたタイマーでチケットをクエリするためにサービスが使用する基本的な SQL クエリを指定します。このクエリはクエリに一意のキーを定義し、送信済みのレコードが再送信されないようにする「キーフィールド名」設定と組み合わされます。

この設定により、新しいチケットをスキャンし、テキストを外部サービスに渡して言語を解析し、オプションとしてこのレスポンスに応じてアドバイザーをリセットする処理が完成しました。では試してみましょう!英語のリクエストを送信してみましょう。これは TicketID 70 で返されます。数秒待ってから、GetTicket REST サービスを介してこのレコードにアクセスすると、アドバイザーは元のリクエストから変わっていないのがわかります。

では、フランス語のテキストを使ってみましょう。

チケット ID 71 をリクエストすると、期待どおり、アドバイザーはフランシスさんに変更されています! これは相互運用性内で、ビジュアルトレースでメッセージの場所を探し、演算が期待どおりに呼び出されたことを確認すればわかります。

この時点でのコード行数は 142 行であり、データを永続させ、LOAD DATA でデータを読み込み、データの表示と編集を行える基本的な REST API と、外部 REST サービスへの呼び出しに基づいて意思決定サポートを提供する高度な統合エンジンを備えた InterSystems IRIS アプリケーションが出来上がりました。これ以上のことを求める人はきっといないですよね?

ステップ 5 - 更なる要求: 分析

このアプリケーションは大成功をおさめ、データもさらに増えています。この貴重データを利用するには専門知識が必要であり、ウィジェットダイレクトの経営陣はインサイトを希望しています。データへの対話型アクセスを提供できるでしょうか?

InterSystems IRIS Analytics を使用すると、高度なデータ操作ツールを素早く簡単に利用できます。まずは、内部 Web アプリケーションに対し、Analytics サポートを有効化する必要があります。

これにより、ネームスペースの分析セクションを使用できるようになります。「分析」>「アーキテクト」を開きましょう。「新規」を選択してフォームに入力し、Ticket クラスの分析キューブを作成します。

次に、ビジュアルビルダーを使って、次元と、基本的なドリルダウンのリストをセットアップします。このビューはドラッグアンドドロップで操作します。リストは、ユーザーがデータポイントを調査する際に表示されるコンテンツをカスタマイズするためのビジュアルエディターででも作成できます。

基本のセットアップが完了したら、キューブを保存、コンパイル、ビルドできます。これによりすべてのインデックスがセットアップされ、アナライザーでの分析用にキューブが有効化されます。アナライザーを開いてデータを操作してみましょう。例では、アドバイザーを年と四半期の階層に対して比較されており、保存されている連絡先でフィルターされています。セルをクリックすると双眼鏡のアイコンが表示されるため、それをクリックすると作成したドリルダウンリストが呼び出されます。それを使用してさらに分析し、エクスポートすることができます。

まとめ

たった 142 行のコードで、基本的ではありながらも機能性のあるモダンなバックエンドアプリケーションを作成しました。アプリケーション間の通信と高度な分析が可能なツールもサポートされています。これは過剰に単純化した実装であり、IRIS でデータベースアプリケーションを構築するために必要最低限の例としてのみ使用してください。この記事の冒頭で述べたように、このコードは本番対応かつ実用できるものではありません。開発者は InterSystems IRIS ドキュメントとベストプラクティスを参考にしながら、自分のコードを堅牢かつ安全で、スケーラブルにしてください(このコードベースはどれにも該当しません)。それでは、コーディングをお楽しみください!

1
0 131
記事 Toshihiko Minamoto · 3月 25, 2024 10m read

バージョン 2023.3(InterSystems IRIS for Health)の新機能は、FHIR プロファイル基準の検証を実行する機能です。

(*)

この記事では、この機能の基本的な概要を説明します。

FHIR が重要な場合は、この新機能を絶対にお試しになることをお勧めします。このままお読みください。

 

背景情報

FHIR 規格は、$validate という演算を定義します。 この演算は、リソースを検証する API を提供することを意図しています。

FHIR Validation に関する概要を理解するには、こちらの FHIR ドキュメントをご覧ください。

また、Global Summit 2023 での私の「Performing Advanced FHIR Validation」セッションもご覧ください。最初の方で、様々な種類の検証に関する情報を提供しています。

この検証の一部は、特定のプロファイルに対する検証です。 プロファイリングについてはこちらをご覧ください。

簡単な例として、Patient Resource の基本的な FHIR 定義では、識別子の基数を '0..*' として定義します。つまり、Patient には識別子が何もなく(ゼロ)、それでも有効であるということです。 しかし、US Core Patient Profile は、'1..*' の帰趨を定義しています。つまり、Patient に識別子がない場合、有効ではないということになります。

別の例では、上記の US Core Patient の例に従うと、race や birthsex などの拡張が使用されることがあります。

FHIR Profiling についての詳細は、Global Summit 2022 で @Patrick Jamieson が講演した 「Using FHIR Shorthand」セッションをご覧ください。Pat が FSH(FHIR の略)の使用について説明していますが、Profiling の一般的なトピックの説明から始まっています。

以前のバージョンでは、FHIR Server はこの種(プロファイルベース)の検証をサポートしていませんでしたが、最新バージョン(2023.3)からはサポートされています。

使用方法

ドキュメントには、プロファイルベースの検証に $validate を呼び出す方法についてのセクションが含まれています。

$validate 演算を呼び出す基本的な方法には 2 つあります。

クエリ URL でのプロファイリング

1 つ目は、Request Body の Resource と URL パラメーターとしてのプロファイルを含めた POST 送信です。

たとえば、Postman では:

または curl を使用(プロファイル URL パラメーターの値のスラッシュのエンコーディングに注意してください。Postman によって処理されます):

 curl --location 'http://fhirserver/endpoint/Patient/$validate?profile=http%3A%2F%2Fhl7.org%2Ffhir%2Fus%2Fcore%2FStructureDefinition%2Fus-core-patient' --header 'Content-Type: application/fhir+json' --header 'Accept: application/fhir+json' --header 'Authorization: Basic U3VwZXJVc2VyOnN5cw==' --data "@data.json"

上記で参照される data.json には、例としてこの有効な US Core Patient が含まれています。

{
  "resourceType" : "Patient",
  "id" : "example",
  "meta" : {
    "profile" : ["http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient|7.0.0-ballot"]
  },
  "text" : {
    "status" : "generated",
    "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p style=\"border: 1px #661aff solid; background-color: #e6e6ff; padding: 10px;\"></div>"
  },
  "extension" : [{
    "extension" : [{
      "url" : "ombCategory",
      "valueCoding" : {
        "system" : "urn:oid:2.16.840.1.113883.6.238",
        "code" : "2106-3",
        "display" : "White"
      }
    },
    {
      "url" : "ombCategory",
      "valueCoding" : {
        "system" : "urn:oid:2.16.840.1.113883.6.238",
        "code" : "1002-5",
        "display" : "American Indian or Alaska Native"
      }
    },
    {
      "url" : "ombCategory",
      "valueCoding" : {
        "system" : "urn:oid:2.16.840.1.113883.6.238",
        "code" : "2028-9",
        "display" : "Asian"
      }
    },
    {
      "url" : "detailed",
      "valueCoding" : {
        "system" : "urn:oid:2.16.840.1.113883.6.238",
        "code" : "1586-7",
        "display" : "Shoshone"
      }
    },
    {
      "url" : "detailed",
      "valueCoding" : {
        "system" : "urn:oid:2.16.840.1.113883.6.238",
        "code" : "2036-2",
        "display" : "Filipino"
      }
    },
    {
      "url" : "text",
      "valueString" : "Mixed"
    }],
    "url" : "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race"
  },
  {
    "extension" : [{
      "url" : "ombCategory",
      "valueCoding" : {
        "system" : "urn:oid:2.16.840.1.113883.6.238",
        "code" : "2135-2",
        "display" : "Hispanic or Latino"
      }
    },
    {
      "url" : "detailed",
      "valueCoding" : {
        "system" : "urn:oid:2.16.840.1.113883.6.238",
        "code" : "2184-0",
        "display" : "Dominican"
      }
    },
    {
      "url" : "detailed",
      "valueCoding" : {
        "system" : "urn:oid:2.16.840.1.113883.6.238",
        "code" : "2148-5",
        "display" : "Mexican"
      }
    },
    {
      "url" : "text",
      "valueString" : "Hispanic or Latino"
    }],
    "url" : "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity"
  },
  {
    "url" : "http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex",
    "valueCode" : "F"
  }
  ],
  "identifier" : [{
    "use" : "usual",
    "type" : {
      "coding" : [{
        "system" : "http://terminology.hl7.org/CodeSystem/v2-0203",
        "code" : "MR",
        "display" : "Medical Record Number"
      }],
      "text" : "Medical Record Number"
    },
    "system" : "http://hospital.smarthealthit.org",
    "value" : "1032702"
  }],
  "active" : true,
  "name" : [{
    "use" : "old",
    "family" : "Shaw",
    "given" : ["Amy",
    "V."],
    "period" : {
      "start" : "2016-12-06",
      "end" : "2020-07-22"
    }
  },
  {
    "family" : "Baxter",
    "given" : ["Amy",
    "V."],
    "suffix" : ["PharmD"],
    "period" : {
      "start" : "2020-07-22"
    }
  }],
  "telecom" : [{
    "system" : "phone",
    "value" : "555-555-5555",
    "use" : "home"
  },
  {
    "system" : "email",
    "value" : "amy.shaw@example.com"
  }],
  "gender" : "female",
  "birthDate" : "1987-02-20",
  "address" : [{
    "use" : "old",
    "line" : ["49 MEADOW ST"],
    "city" : "MOUNDS",
    "state" : "OK",
    "postalCode" : "74047",
    "country" : "US",
    "period" : {
      "start" : "2016-12-06",
      "end" : "2020-07-22"
    }
  },
  {
    "line" : ["183 MOUNTAIN VIEW ST"],
    "city" : "MOUNDS",
    "state" : "OK",
    "postalCode" : "74048",
    "country" : "US",
    "period" : {
      "start" : "2020-07-22"
    }
  }]
}

この演算のリソースは OperationOutcome Resource です。

Resource が有効(上記のとおり)である場合、この種のレスポンスが得られます。

{
    "resourceType": "OperationOutcome",
    "issue": [
        {
            "severity": "information",
            "code": "informational",
            "details": {
                "text": "All OK"
            }
        }
    ]
}

ただし、例えば上記の Resource から識別子を省略すると、この OperationOutcome が得られます。

{
    "resourceType": "OperationOutcome",
    "issue": [
        {
            "severity": "error",
            "code": "invariant",
            "details": {
                "text": "generated-us-core-patient-1: Constraint violation: identifier.count() >= 1 and identifier.all(system.exists() and value.exists())"
            },
            "diagnostics": "Caused by: [[expression: identifier.count() >= 1, result: false, location: Patient]]",
            "expression": [
                "Patient"
            ]
        }
    ]
}

クエリ本文でのプロファイリング

データを $validate に送信するもう 1 つの方法は、Parameters 配列内のリソースをプロファイルやその他のオプションとともに指定して POST 送信することです。

Postman では、これは以下のようになります。

curl を使用した場合:

curl --location 'http://fhirserver/endpoint/Patient/$validate' --header 'Content-Type: application/fhir+json' --header 'Accept: application/fhir+json' --header 'Authorization: Basic U3VwZXJVc2VyOnN5cw==' --data "@data.json"

URL にはプロファイルは含まれませんが、ボディのペイロード(または上記の例の data.json)は以下のようになります。

{
    "resourceType": "Parameters",
    "parameter": [
        {
            "name": "mode",
            "valueString": "profile"
        },
        {
            "name": "profile",
            "valueUri": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
        },
        {
            "name": "resource",
            "resource": {
                "resourceType": "Patient"
                
               
            }
        }
    ]
}

実際の Patient Resource は前の例と同じであるため除外しました。

ただし、ここで異なるのは、mode パラメーター要素と profile パラメーター要素であり、リソースは「resource」という独自のパラメーター要素内に含まれています。

ID が URL のどこに含まれるかなど(たとえば、更新または削除を検証するため)、mode のその他のオプションについては、上記で参照したドキュメントをご覧ください。

便宜上、上記のサンプルリクエストなどの Postman コレクションを含む単純な Open Exchange パッケージを作成しました。

コードを使用

標準 REST API 経由で $validate 演算を呼び出す代わりに、ユースケースが適切であれば、内部的にクラスメソッドを呼び出すこともできます。

既存の HS.FHIRServer.Util.ResourceValidator:ValidateResource() メソッド(こちらのドキュメントでも説明)と同様に、ValidateAgainstProfile() という新しいメソッドも追加されており、それを利用できます。

 

範囲

現在(v2023.3)では、この種の検証(プロファイル基準の検証)は $validate 演算の一部としてのみ行われ、Resource の作成や更新時には行われないことに注意しておくことが重要です。 そこでは、より「基本的な」検証が行われます。 必要であれば、より「高度な」プロファイル基準の検証を使って、POST または PUT される前に Resouce を実行することができます。

別のオプションも、今後のバージョンで提供される可能性があります。

セットアップに関する注意事項

一般に、FHIR Server がほとんどの Profile Validator セットアップを処理します。

確認が必要なのは、サポートされている Java 11 JDK がインストールされていることです(現在、Oracle のものか OpenJDK のもの)。

詳細は、Profile Validation Server の構成に関するドキュメントをご覧ください。

基本的に、Validator JAR を実行するために、外部言語(Java)サーバーが実行中であることが確認されています(JAR ファイルはインストールフォルダの dev/fhir/java にあります。ちなみに、logs フォルダを覗くと、以下のような警告が表示されます:

CodeSystem-account-status.json : Expected: JsonArray but found: OBJECT for element: identifier

気にする必要はありません。 Validator はデフォルトで多数のプロファイルを読み込むものであり、その一部にはフォーマットエラーがあります)。

つまり、外部言語サーバーのリストを見ると、以下のようなものを確認できます。

Validator がプロファイルに対して検証する必要がある場合、初めてプロファイルをロードする必要があることに注意してください。そのため、パフォーマンスを向上させるために、HS.FHIRServer.Installer:InitalizeProfileValidator() メソッドを呼び出すことができます。

do##class(HS.FHIRServer.Installer).InitializeProfileValidator()

これについても上記で参照したドキュメントには、Validator の構成に関して説明されています。

実際、この呼び出しをインスタンスの %ZSTART 起動ルーチンに含めることもできます。

また、これについても関連するクラスリファレンスで説明されています。

このメソッドは、検証操作中にプロファイルを読み込むことによるパフォーマンスへの影響がないように、インスタンスまたは外部言語サーバーの再起動後に呼び出すことが推奨されています。

今後の予定

今後のバージョンでは、Validator 内と Validator 周りにより多くの機能を提供する予定です。

ただし、例えば現時点でも、外部用語サーバーを使った検証(LOINC コードなど)を実行する場合、別のアプローチを使用することができます。1 つは、前述の Global Summit セッションで説明と実践が行われている方法で、同僚の @Dmitry Zasypkin のサンプル(Open Exchange で提供)に基づくものです。

謝辞

この新機能を調べながらこの記事を準備するにあたって貴重な情報を提供してい頂いた @Kimberly Dunn にお礼申し上げます。

(*)Microsoft Bing の DALL-E 3 を使用して上記の画像を作成してくれた画像クリエーターに感謝しています。

0
1 207
お知らせ Mihoko Iijima · 3月 7, 2024

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

インターシステムズの講師付きトレーニング「システム統合機能(Interoperability)の使い方」3日間(有料)を下記日時で開催します!

 

開催方法は、Teams会議とブラウザ経由でアクセスする演習環境(Windows)を利用したオンラインでの開催です。(ブラウザと安定したネットワーク環境があれば特にその他準備は不要です。)

コースでは、InterSystems IRIS または InterSystems IRIS for Health(以降IRIS)のインストールから開始し、開発環境の作成、VSCodeを利用した簡単なクラス定義の作成、ObjectScriptを使用したオブジェクト操作の練習を行った後、本題のシステム統合機能(Interoperabiityメニュー)の解説と演習に入ります。

コースで用意している外部システムへのアクセスとしては、データベースとファイル入出力があります。進み具合にもよりますが、お時間ある時はREST経由で情報を受信する方法も演習いただけます。

なお、Interoperabilityについては、コミュニティのシリーズ記事「【はじめてのInterSystems IRIS】Interoperability(相互運用性)を使ってみよう!」でもご紹介しています。

0
0 62
記事 Mihoko Iijima · 3月 6, 2024 2m read

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

Ens.Directorクラスのクラスメソッドを使用して取得できます。

プロダクション名(FAQSample.Interop.Production)とホスト名(FAQSample.Interop.FileOperation)を指定して設定リストを取得する方法は以下の通りです。

Set status=##class(Ens.Director).GetHostSettings("FAQSample.Interop.Production||FAQSample.Interop.FileOperation",.tSettings)

 以下、出力結果です。

0
0 108
記事 Mihoko Iijima · 2月 27, 2024 7m read

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

InterSystems製品のInteroperability(相互運用性機能)を利用する際、REST経由で情報入力を行う場合の作成方法についてサンプルプロダクションを利用しながらご紹介します。

サンプルはこちら👉https://github.com/Intersystems-jp/FAQ-Interop-REST

0
0 199
お知らせ Mihoko Iijima · 1月 15, 2024

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

InterSystems FHIR とデジタルヘルスの相互運用性コンテスト のテクノロジーボーナス詳細が決定しましたのでお知らせします。

  • InterSystems FHIR の使用 - 3
  • InterSystems FHIR SQL Builder の使用 - 3
  • デジタルヘルスの Interoperability(相互運用性) - 4
  • LLM AI または LangChain の利用: Chat GPT、Bard、その他 - 3
  • Embedded Python - 2
  • Questionnaireの利用 - 2
  • IRIS For Health Instruqt Interoperability アンケートのへの回答 - 1
  • Docker コンテナの利用 - 2 
  • IPM Package によるデプロイ - 2
  • オンラインデモ - 2
  • InterSystems Community Idea の実装 - 4
  • InterSystems FHIR server のBugを見つける - 2
  • InterSystems Interoperability のBugを見つける - 2
  • コミュニティ(USコミュニティ)に記事を投稿する(最初の記事)- 2
  • コミュニティ(USコミュニティ)に2つ目の記事を投稿する - 1
  • 初めて参加した方 - 3
  • YouTubeにビデオを公開 - 3

詳細は以下の通りです。<--break->

0
0 115
記事 Toshihiko Minamoto · 12月 28, 2023 35m read

はじめに {#Webinar:ImplementingIntegrationswith.NetorJava-Introduction}

InterSystems IRIS 2020.1 には、Java または .NET で記述されたコンポーネントで IRIS 相互運用性プロダクションの開発を容易にする PEX(プロダクション拡張フレームワーク)が含まれています。

この PEX により、Java または .NET の知識を備える統合開発者は、InterSystems IRIS 相互運用性フレームワークの力、スケーラビリティ、および堅牢性を利用し、すぐに生産性を高めることができます。

IRIS 相互運用性フレームワークエキスパートに対し、PEX は既存の Java 言語または .NET 言語の外部コンポーネントとの統合を簡単にリッチ化することができます。

このチュートリアルでは、PEX を詳しく見ながら、.NET 開発者による PEX のはじめての使用を説明します。 コードは、https://github.com/es-comunidad-intersystems/webinar-PE にあります。

このチュートリアルは、https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=EPEX にあるオンライン PEX ドキュメントを補足するものです。

 

InterSystems IRIS 相互運用性のアーキテクチャ {#Webinar:ImplementarIntegracionescon.NetoJava-ArquitecturadeInteroperabilidadInterSystemsIRIS}

PEX では、任意のプログラミング言語(現時点では Java または .NET。将来的に Python も追加)を選択して、IRIS 相互運用性プロダクションを形成するコンポーネント(ビジネスサービス、ビジネスプロセス、ビジネスオペレーション、インバウンドアダプター、アウトバウンドアダプター、メッセージ)を実装できます。

IRIS 相互運用性には主に 3 つのコンポーネントがあります。

  • ビジネスサービス: 外部から使用できるサービスを提供するコンポーネント。 ビジネスサービスの例には REST サービスや SOAP Web サービスがありますが、ディレクトリに書き込まれた新しいファイルの読み取りと処理を行うサービス、データベーステーブルの行の読み取りと処理を行うサービス、FTP 経由でファイルを読み取るサービスなどもあります。 ビジネスサービスにはインバウンドアダプターが関連付けられる場合があり、特定のプロトコルの実装情報を管理します(SQL テーブルを読み取る SQLInboundAdapter、ファイルを読み取る FileInboundAdapter など)。 ビジネスサービスは、情報の処理、IRIS 相互運用性メッセージへの情報のコピー、およびビジネスプロセスまたはビジネスオペレーションへのメッセージの送信とレスポンスがある場合はその待機などを行います。  
  • ビジネスオペレーション: IRIS 相互運用性メッセージを受け取り、外部システムで稼働するコンポーネント。プロトコル実装情報(TCP、REST、SOAP、Files、SQL など)を管理する OutboundAdapter を使用する場合があります。 ビジネスオペレーションは呼び出し元にレスポンスを返す場合とそうでない場合があります。  
  • ビジネスプロセス: IRS 相互運用性メッセージを受信する際に 1 つ以上の他のビジネスプロセスまたはオペレーションを処理して呼び出しを行い、複雑なオペレーションを実行したり、それを送信したビジネスサービスに情報を追加してメッセージ返したりするオーケストレーションプロセスです。

コンポーネント構成は、「Production」にグループ化されます。これは、IRIS が起動する際にまとめて起動するすべての統合の定義と、これらの統合の各コンポーネントの構成を含む InterSystems IRIS クラスです。 IRIS クラスとして編集するか、管理ポータルから変更できます。

 

PEX のアーキテクチャ {#Webinar:ImplementarIntegracionescon.NetoJava-ArquitecturadePEX}

.NET または Java コードを実行するために、InterSystems IRIS は対応するオブジェクトゲートウェイを使用します。 このゲートウェイはローカルまたはリモートサーバー上にインスタンス化できます。

Java と .NET ゲートウェイ {#Webinar:ImplementarIntegracionescon.NetoJava-LosJavay.NetGateways}

ゲートウェイは、特定の TCP/IP ポートをリッスンし、IRIS プロセスからのリクエストを受信して実行し、結果を返すネイティブの .NET または Java コンポーネントです。

ビルド済みの PEX コンポーネント {#Webinar:ImplementarIntegracionescon.NetoJava-LosComponentesPEXpre-construidos}

IRIS プロダクションで PEX を使用するには、Java または .NET で開発されたコンポーネントごとに、ビルド済みのコンポーネントをプロダクションに追加する必要があります。 ビルド済みのコンポーネントはそれが参照する外部要素のラッパーとして機能し、そのプロパティと構成をプロダクション内で定義することができます。

対応するゲートウェイから実行している Java または .NET コンポーネントは、既存の PEX コンポーネントを継承している(サブクラス化される)必要があります。 これらの要素の概要を以下に示します。

IRIS コンポーネント {#Webinar:ImplementarIntegracionescon.NetoJava-ComponentesdeIRIS}

.NET と Java 用

<th>
  クラス
</th>

<th>
  コメント
</th>
<td>
  EnsLib.PEX.BusinessService
</td>

<td>
  構成されるアダプター: Ens.InboundAdapter
</td>
<td>
  EnsLib.PEX.BusinessProcess
</td>

<td>
   
</td>
<td>
  EnsLib.PEX.BusinessOperation
</td>

<td>
   
</td>
<td>
  EnsLib.PEX.InboundAdapter
</td>

<td>
   
</td>
<td>
  EnsLib.PEX.OutboundAdapter
</td>

<td>
   
</td>
<td>
  EnsLib.PEX.Message
</td>

<td>
  PEX コンポーネントに送信するメッセージ
</td>
<td>
  IRIS メッセージにマッピング
</td>

<td>
  IRIS コンポーネントへの PEX コンポーネントのメッセージ
</td>
機能
ビジネスサービス
ビジネスプロセス
ビジネスオペレーション
インバウンドアダプター
アウトバウンドアダプター
PEX メッセージ
IRIS メッセージ

 

Java または .NET コンポーネント

これらのコンポーネントは Java または .NET プロジェクトに追加されるライブラリに提供されています。 PEX プロジェクトで参照する最低限のライブラリは、ゲートウェイのライブラリと同じです。 また、IRISObject メッセージを使って PEX から IRIS コンポーネントを呼び出す場合、IRISClient ライブラリを参照する必要があります。

<th>
  ライブラリ
</th>
<td>
  &lt;installdir>\dev\dotnet\bin\v4.5\InterSystems.Data.Gateway64.exe 
  &lt;installdir>\dev\dotnet\bin\v4.5\InterSystems.Data.IRISClient.dll
</td>
<td>
  &lt;installdir>\dev\java\lib\JDK18\intersystems-gateway-3.1.0.jar 
  &lt;installdir>\dev\java\lib\JDK18\intersystems-jdbc-3.1.0.jar 
  &lt;installdir>\dev\java\lib\gson\gson-2.8.5.jar
</td>
言語
.NET
Java

 

.NET コンポーネントに使用するスーパークラス

<th>
  .NET クラス
</th>
<td>
  InterSystems.EnsLib.PEX.BusinessService
</td>
<td>
  InterSystems.EnsLib.PEX.BusinessProcess
</td>
<td>
  InterSystems.EnsLib.PEX.BusinessOperation
</td>
<td>
  InterSystems.EnsLib.PEX.InboundAdapter
</td>
<td>
  InterSystems.EnsLib.PEX.OutboundAdapter
</td>
<td>
  InterSystems.EnsLib.PEX.Message
</td>
<td>
  InterSystems.Data.IRISClient.ADO.IRISObject
</td>
機能
ビジネスサービス
ビジネスプロセス
ビジネスオペレーション
インバウンドアダプター
アウトバウンドアダプター
PEX メッセージ
IRIS メッセージ

 

Java コンポーネントに使用するスーパークラス

<th>
  Java クラス
</th>
<td>
  com.intersystems.enslib.BusinessService
</td>
<td>
  com.intersystems.enslib.BusinessProcess
</td>
<td>
  com.intersystems.enslib.BusinessOperation.
</td>
<td>
  com.intersystems.enslib.pex.InboundAdapter
</td>
<td>
  com.intersystems.enslib.pex.OutboundAdapter
</td>
<td>
  com.intersystems.enslib.pex.Message
</td>
<td>
  &lt;...>.IRISObject
</td>
機能
ビジネスサービス
ビジネスプロセス
ビジネスオペレーション
インバウンドアダプター
アウトバウンドアダプター
PEX メッセージ
IRIS メッセージ

 

ユーティリティ関数 {#Webinar:ImplementarIntegracionescon.NetoJava-FuncionesdeUtilidades}

ObjectScript に実装されているコンポーネントでは、InterSystems IRIS は、マクロの形式で IRIS イベントログに情報を入力するためのコマンドをいくつか提供しています。 これらのメソッドは、以下のように Java と .NET で使用できます。

<th>
  説明
</th>
<td>
  「info」ステータスのメッセージをイベントログに追加します。
</td>
<td>
  「alert」ステータスのメッセージをイベントログに追加します。
</td>
<td>
  「warning」ステータスのメッセージをイベントログに追加します。
</td>
<td>
  「error」ステータスのメッセージをイベントログに追加します。
</td>
<td>
  「assert」ステータスのメッセージをイベントログに追加します。
</td>
メソッド
LOGINFO(message)
LOGALERT(message)
LOGWARNING(message)
LOGERROR(message)
LOGASSERT(message)

 

ネイティブコンポーネントと PEX コンポーネントの相互運用性 {#Webinar:ImplementarIntegracionescon.NetoJava-InteroperabilidadentrecomponentesnativosycomponentesPEX}

InterSystems IRIS のネイティブ ObjectScript 言語のコンポーネントと Java または .NET で開発された PEX コンポーネントを組み合わせることが可能です。

  • 両方のコンポーネントが BusinessService タイプと InboundAdapter または BusinessOperation と OutboundAdapter である場合、開発者は呼び出しに使用するデータ/オブジェクトのタイプを選択できます。呼び出しは IRIS と Java/.NET ゲートウェイの間で、ゲートウェイを判定するデータ変換ルールに従って行われます。
  • 情報を交換する両方のコンポーネントがビジネスホスト(BS、BP、BO)である場合、メッセージ(リクエストまたはレスポンス)を受け取るコンポーネントがは、メッセージに使用するオブジェクトのタイプを強制します。
    • PEX コンポーネントは常にメッセージ EnsLib.PEX.Message を受信します。
    • IRIS コンポーネントはメッセージ IRISObject を受信します。

EnsLib.PEX.Message {#Webinar:ImplementarIntegracionescon.NetoJava-EnsLib.PEX.Message}

EnsLib.PEX.Message を使用すると、.NET または Java で定義された構造のメッセージを IRIS ObjectScript で表現できます。 IRIS は DynamicObject 関数を使用してプロパティを操作します。 内部的には、IRIS は JSON を IRIS と .NET/Java 間のトランスポート媒体として使用します。 IRIS で PEX メッセージを作成する際、メッセージを使用するためにインスタンス化される必要のある .NET/Java クラスの名前は %classname として設定される必要があります。

IRISObject {#Webinar:ImplementarIntegracionescon.NetoJava-IRISObject}

ビルド済みの InterSystems IRIS コンポーネントを PEX コンポーネントから呼び出すには、IRISObject タイプのメッセージが定義されている必要があります(.NET では、完全なクラスは InterSystems.Data.IRISClient.ADO.IRISObject です)。

PEX と .NET の最初のステップ {#Webinar:ImplementarIntegracionescon.NetoJava-PrimerosPasosconPEXy.NET}

最初のステップでは、以下を行います。

  • 必要な PEX ライブラリ、.NET フレームワークバージョン 4.5 を使って .NET プロジェクトを作成する
  • .NET プロジェクトに BusinessOperation と単純なメッセージを追加する
  • InterSystems IRIS の .NET ゲートウェイを構成する
  • 相互運用性プロダクションを作成する
  • ビルド済みの BO を追加する

Visual Studio 2019 で .NET プロジェクトを作成する {#Webinar:ImplementingIntegrationswith.NetorJava-Creatinga.NETProjectwithVisualStudio2019}

Visual Studio で新しい「Class Library .Net Standard in C #」タイプのプロジェクトを作成します。 これを「PEX.Webinar.FirstDemo」とします。

PEX を操作するには、「Solution Explorer」と「Add Reference(参照を追加)」コンテキストメニューから必要な依存関係を追加します。

次に「Browse(参照)」ボタンを使って、2 つのライブラリ(.NET Framework 4.5! 対応)を追加します。これは、InterSystems IRIS インストールのサブディレクトリにあります。

<installdir>\dev\dotnet\bin\v4.5\InterSystems.Data.Gateway64.exe <installdir>\dev\dotnet\bin\v4.5\InterSystems.Data.IRISClient.dll

ソリューション Explorer Class 1.cs から「FirstOperation.cs」に名前が変更され、クラスは BusinessOperation PEX クラス(InterSystems.EnsLib.PEX.BusinessOperation)から継承するように変更されます。 すべての 3 つの PEX.BusinessOperation メソッドは上書きされています。

<th>
  説明
</th>
<td>
  このコンポーネントがプロダクションで開始されるときに 1 回実行します。 これにより、ライブラリ、接続、および変数を起動できるようになります...
</td>
<td>
  このコンポーネントまたはプロダクションが停止するときに 1 回実行します。 コンポーネントのライフサイクルで使用されたリソースを解放できるようになります。
</td>
<td>
  受信するメッセージごとに実行します。 メッセージを処理し、レスポンスを返すことができます。
</td>
メソッド
OnInit
OnTearDown
OnMessage

 

この時点では、メッセージや実行するタスクは定義されていません。 そのため、LOGINFO 関数は 3 つのメソッドに追加されています。 一方で、スーパークラスメソッドが呼び出される必要がないため、基底クラス(base.OnInit ()、base.OnTearDown()、base.OnMessage)への呼び出しを除去できます。 実装を以下のようにします。

<th>
  初期デプロイ
</th>
<td>

OnInit

メソッド
OnInit
public override void OnInit()         {             LOGINFO("PEX.Webinar.FirstDemo.FirstOperation:OnInit()");         }
OnTearDown
<td>
  <b>OnTearDown</b>
public override void OnTearDown()        {            LOGINFO("PEX.Webinar.FirstDemo.FirstOperation:OnTearDown()");        }
OnMessage
<td>
  <b>OnMessage</b>
public override object OnMessage(object request)        {            LOGINFO("PEX.Webinar.FirstDemo.FirstOperation:OnMessage()");            return request;        }

 

これにより、「Build Solution」(ソリューションをビルド)メニューで、最初の .NET プロジェクトバージョンをコンパイルできます。 すると IRIS は以下のファイルを生成します。これは次に使用されるファイルです。

1>------ Build started: Project: PEX.Webinar.FirstDemo, Configuration: Debug Any CPU ------ 1>PEX.Webinar.FirstDemo -> C:\Dev\PEX\PEX.Webinar.FirstDemo\bin\Debug\netstandard2.0\PEX.Webinar.FirstDemo.dll ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

InterSystems IRIS 相互運用性プロダクションの作成 {#Webinar:ImplementingIntegrationswith.NetorJava-InterSystemsIRISInteroperabilityProductionCreation}

IRIS 管理ポータルで、「Interoperability」(相互運用性)メニュー、「Ensemble」ネームスペース、および「Configure」(構成)および「Production」(プロダクション)メニューを使用できるようになりました。 「Actions」(アクション)タブと「New」(新規)ボタンを使って、新しい IRIS 統合プロダクションを定義できます。

テストサービスを有効にするには、「Settings」(設定)タブを選択し、リストの最後のセクション(「Development and Debugging」)で「Testing Enabled」を有効にし、Apply(適用)ボタンをクリックします。

.NET ゲートウェイをプロダクションに追加する {#Webinar:ImplementingIntegrationswith.NetorJava-Addingthe.NETGatewaytotheProducción}

PEX を操作するには、対応する Java または .NET ゲートウェイが起動している必要があります。 InterSystems では、プロダクション環境(ライブ)の System Administration(システム管理)/Configuration(構成)/Connectivity(接続)/Object Gateways(オブジェクトゲートウェイ)メニューからこれらのゲートウェイを構成して起動することを推奨しています。 この開発環境においては、コンポーネントをプロダクションに直接追加してゲートウェイを起動することができます。 このため、ワンクリックで、ゲートウェイをプロダクションとして同時に開始・停止できるようになるため、再コンパイルする際に .NET プロジェクトの .DLL へのアクセスを解放することができます(Visual Studio では .NET ゲートウェイが起動している場合に再コンパイルすることができません)。

「.NET Gateway」コンポーネントを追加するには、「Services」(サービス)の横にある「+」ボタンを使用して、プロダクションにビジネスサービスを追加します。 追加されるコンポーネントクラス名(Service クラス)は「EnsLib.DotNetGateway.Service」で、「Enable now」(今すぐ有効化)を選択してこのコンポーネントを有効にします。

追加されたコンポーネントの構成パラメーターは、それをクリックして、「Settings」(設定)タブに値を入力し、「Apply」(適用)ボタンをクリックして編集できます。

<th>
  値
</th>

<th>
  説明
</th>
<td>
  44444
</td>

<td>
  デフォルトのポート 55000 が別のプロセスでビジー状態である場合に、このポートに変更できます。
</td>
<td>
  &lt;installdir>\dev\dotnet\bin\v4.5\
</td>

<td>
  これは、実行可能なゲートウェイ(InterSystems.Data.Gateway64.exe)が存在する場所を示し、 &lt;InstallDir> は IRIS インストールディレクトリです。例: C:\InterSystems\IRIS20201\dev\dotnet\bin\v4.5\
</td>
<td>
  true
</td>

<td>
  64 ビットゲートウェイバージョンを選択します
</td>
<td>
  4.5
</td>

<td>
  .NET バージョンは 4.5 である必要があります
</td>
パラメーター
Port(ポート)
FilePath(ファイルパス)
Exec64
.NET Version(.NET バージョン)

 

.NET で作成されたビジネスオペレーションを追加する  {#Webinar:ImplementingIntegrationswith.NetorJava-AddingtheBusinessOperationcreatedin.NET}

次に、前に作成された .NET コードを参照するために、「Operations」(オペレーション)の横にある「+」ボタンを使用して、PEX ビジネスオペレーションを追加します。 クラスタイプは 「EnsLib.PEX.BusinessOperation」で、(オプションの)コンポーネントは「PEX.Webinar.FirstOperation」と呼ばれます。「Enable Now」を使って有効にされます。

次に、コンポーネントを構成し(追加されたコンポーネントをクリックします)、右側の「Settings」(設定)を選択します。

<th>
  値
</th>

<th>
  説明
</th>
<td>
  PEX.Webinar.FirstDemo.FirstOperation
</td>

<td>
  生成される .NET クラスの名前
</td>
<td>
  44444
</td>

<td>
  .NET ゲートウェイが構成されている TCP ポート
</td>
<td>
  C:\Dev\PEX\PEX.Webinar.FirstDemo\bin\Debug\ netstandard2.0\PEX.Webinar.FirstDemo.dll
</td>

<td>
  含める .DLL の場所。 これは、Visual Studio ビルドが .DLL を生成した場所です。
</td>
パラメーター
Remote Classname(リモートクラス名)
Gateway Port(ゲートウェイポート)
Gateway Extra CLASSPATH(ゲートウェイ追加クラスパス)

変更を適用するために、「Apply」(適用)ボタンをクリックします。

プロダクションを追加してテストする {#Webinar:ImplementingIntegrationswith.NetorJava-AddingandStartingtheProduction}

「Start」(起動)ボタンによって、プロダクションとそのすべてのコンポーネントが起動します。

InterSystems IRIS では、コンポーネントの単純な隔離テストを実施できます。 「PEX.Webinar.FirstOperation」という「ビジネスオペレーション」を選択し、Actions(アクション)タブから「Test」(テスト)ボタンを選択します。

次の画面では以下のようにデータが入力されます。

<th>
  値
</th>

<th>
  説明
</th>
<td>
  EnsLib.PEX.Message
</td>

<td>
  送信される IRIS メッセージのタイプ。 常に EnsLib.PEX.Message です。 Java または .NET PEX コンポーネントに値を渡す動的プロパティを使用できます。
</td>
<td>
  InterSystems.EnsLib.PEX.Message
</td>

<td>
  Java または .NET にコンポーネントリクエストとして定義されるメッセージのクラス名。 .NET の場合、これは InterSystems.EnsLib.PEX.Message またはサブクラスである必要があります。
</td>
パラメーター
リクエストタイプ
%classname

「Invoke Testing Service」(テストサービスを呼び出す)をクリックすると、IRIS 相互運用性フレームワークはメッセージをコンポーネントに送信し、.NET コードが実行されます。

「Visual Trace」(ビジュアルトレース)をクリックすると、詳細を表示できます。 白いドット(#3)は、.NET に実装された「LOGINFO」トレースをひょじします。

IRIS イベントログには、OnInit() と OnTearDown() を含む生成されるすべての LOGINFO() メッセージのコンパイルが含まれます。

PEX での次のステップ: プロダクションの完成 {#Webinar:ImplementingIntegrationswith.NetorJava-NextStepswithPEX:CompletingtheProduction}

以下のように、他のタイプのコンポーネントが .NET で作成されます。

  • .NET メッセージ
  • .NET ビジネスサービス
  • .NET ビジネスプロセス

データによる PEX メッセージの作成と使用 {#Webinar:ImplementingIntegrationswith.NetorJava-CreatingandUsingaPEXMessagewithData}

Ensemble から PEX コンポーネントに情報を渡すために、渡される情報のプロパティを使って、サブクラス InterSystems.EnsLib.PEX.Message として、.NET でクラスを定義します。 単純化された例をそのまま使用し、メッセージに文字列「value」プロパティを追加します。 PEX ビジネスオペレーションは、コンテンツが大文字に変換された同じタイプのメッセージになります。

.NET のメッセージクラス {#Webinar:ImplementarIntegracionescon.NetoJava-Clasedemensajeen.NET}

新しい「FirstMessage.cs」ファイルは、以下の定義を使って .NET プロジェクトに追加されます。

FirstMessage

using System; using System.Collections.Generic; using System.Text; namespace PEX.Webinar.FirstDemo {     class FirstMessage : InterSystems.EnsLib.PEX.Message     {         public string value;     } }

.NET からメッセージを使用する {#Webinar:ImplementarIntegracionescon.NetoJava-Usodelmensajedesde.NET}

FirstOperation ビジネスオペレーションでは、OnMessage のデータ型はオブジェクトとして定義されます。 これを使用するには、「FirstMessage」クラスにキャストする必要があります。

OnMessageV2

public override object OnMessage(object request)         {             LOGINFO("PEX.Webinar.FirstDemo.FirstOperation:OnMessage()");             ///レスポンスメッセージがインスタンス化             FirstMessage response = new FirstMessage();             //値がリクエストから「uppercase」でコピーされる             response.value = ((FirstMessage)request).value.ToUpper();             //レスポンスが返される             return response;         }

IRIS プロダクションを停止する(「Stop」(停止)ボタンを使用)か、少なくとも .NET ゲートウェイを無効にして(コンポーネントをダブルクリック)、.NET プロジェクトをコンパイルする必要があります。

InterSystems IRIS からクラスを使用する {#Webinar:ImplementarIntegracionescon.NetoJava-UsodelaclasedesdeInterSystemsIRIS}

「Test」(テスト)ボタン(テストサービス)では、EnsLib クラスの動的プロパティを filled.PEX.Message にできません。 ただし、テストサービスは IRIS ネイティブの「Ens.StringRequest」メッセージタイプとともに使用でき、(データ変換を通じて)PEX メッセージに変換することができます。 変換は、ビルド済みのルータータイプのビジネスプロセスから呼び出されます。

データ変換 {#Webinar:ImplementingIntegrationswith.NetorJava-DataTransformation}

データ変換は、データをネイティブ Ensemble メッセージからコピーするために作成されます。

<th>
  ソース
</th>

<th>
  ターゲット
</th>

<th>
  コメント
</th>
<td>
  EnsLib.StringRequest
</td>

<td>
  EnsLib.PEX.Message
</td>

<td>
  変換ソースとターゲットのクラス
</td>
<td>
  該当なし
</td>

<td>
  PEX.Webinar.FirstDemo.FirstMessage
</td>

<td>
  PEX メッセージ(ターゲット)の場合、%classname は、使用される .NET/Java クラス名を定義します。
</td>
<td>
  source.StringValue
</td>

<td>
  target.%jsonObject.value
</td>

<td>
  ターゲット PEX メッセージでは、動的プロパティは %jsonObject 内にあります。
</td>
 
クラス
%classname
プロパティ

 

データ変換は、管理ポータルの「Interoperability」>「ビルド」>「データ変換」にある「New」(新規)ボタンを使用して作成できます。

その後、「ソース」から「ターゲット」メッセージへの変換のパラメーターは、グラフィックツールを使用して、下に表示される 2 行のテキストを取得するように右側の「Action」(アクション)タブにテキストを入力することで、前のテーブルで説明されたとおりに定義されます。 すると、「Tools」(ツール)タブで保存、コンパイル、およびテストすることができます。

次に、「Tools」(ツール)タブを開いて、このデータ変換をテストできます。

ソースメッセージの値を指定(StringValue)して、結果を検証できるテストウィンドウが開きます。

ご覧のとおり、PEX メッセージは内部 JSON 表現を使用して、IRIS と Java または .NET 間で値を送信しています。

ルータータイプのビジネスプロセスを作成する {#Webinar:ImplementingIntegrationswith.NetorJava-CreatingaRoutertypeBusinessProcess}

ルータータイプのビジネスプロセスをプロダクションに追加し、作成されるデータ変換を呼び出して既存のビジネスオペレーションにメッセージを送信するルーティングルールを定義できるようになりました。

管理ポータルで、「Production Configuration」(プロダクション構成)画面(「Interoperability」/「構成」/「プロダクション」)に戻り、「Processes」(プロセス)の横にある「+」をクリックして以下のように入力し、ビジネスプロセスタイプ「EnsLib.Message.Router」を追加します。

<th>
  値
</th>

<th>
  説明
</th>
<td>
  EnsLib.MsgRouter.RoutingEngine
</td>

<td>
  ルールベースのメッセージルーティングを行うビジネスプロセス
</td>
<td>
  TRUE
</td>

<td>
  ルーティングルールのスケルトンを定義します
</td>
<td>
  MessageRouter
</td>

<td>
  プロダクションにおけるこのコンポーネントの名前
</td>
<td>
  TRUE
</td>

<td>
  このコンポーネントを直ちに有効化します
</td>
<td>
  1
</td>

<td>
  スケーラビリティ。 同時に実行するアクティブプロセス数を定義できます。
</td>
パラメーター
Business Process Class(ビジネスプロセスクラス)
Auto-Create Rule(自動作成ルール)
Business Process Name(ビジネスプロセス名)
Enable Now(今すぐ有効化)
Pool Size(プールサイズ)

 

このコンポーネントのルーティングルールの編集が残っています。 これを行うために、プロダクションの「MessageRouter」コンポーネントを選択し、ビジネスルール名の横にある虫眼鏡をクリックします。

ルールエディターでは、変換が適用された後に、すべての「Ens.StringRequest」メッセージを「PEX.Webinar.FirstOperation」ビジネスオペレーションに送信するようにルールを編集できます。 「+」ボタンを使用すると、ルールに要素を追加し、あらかじめ要素を選択する際には要素を編集することができます。 以下のようにルールを作成します。

デフォルトでは、このコンポーネントはレスポンスを期待しません。 コンポーネントの「Settings」(設定)タブで、ビジネスオペレーションからレスポンスを受信するように設定を変更しましょう。

テストサービスでルーターをテストする {#Webinar:ImplementarIntegracionescon.NetoJava-PruebadelEnrutadorconelServiciodePruebas}

プロダクションページに戻り、「Start」(起動)ボタンを使ってプロダクションを起動し、「MessageRouter」コンポーネントを選択します。「Actions」(アクション)タブで、「Test」(テスト)ボタンをクリックし、「Ens.StringRequest」タイプのメッセージを送信します。

テストレスポンスメッセージを「Test Results」(テスト結果)で確認できます。完全なメッセージログには、IRIS 相互運用性プロダクションの様々なコンポーネントに関する実行の全詳細が表示されます。

レスポンス:

  {#Webinar:ImplementarIntegracionescon.NetoJava-}

メッセージのトレース:

.NET ビジネスサービス {#Webinar:ImplementarIntegracionescon.NetoJava-BusinessServiceen.NET}

.NET の実装 {#Webinar:ImplementingIntegrationswith.NetorJava-Implementationin.NET}

Visual Studio に戻り、.NET ビジネスサービスを作成します。 この最初の例では、このビジネスサービスに特定の「インバウンドアダプター」は関連付けられていません。(CallInterval 値の設定に従って)定期的に実行し、CallInterval ごとにビジネスサービスを呼び出す「EnsLib.InboundAdapter」コンポーネントを使用します。 

Visual Studio で、「FirstService」クラスの新しい「FirstService.cs」ファイルが生成されます。 インバウンドアダプターが検出する各イベントの処理は、「OnProcessInput」メソッドを使って行われます。 パラメーターに設定されるオブジェクトは、InboudAdapter の実装によって異なりますが、この場合は使用されていません。

FirstService:OnProcessInput

public override object OnProcessInput(object messageInput)         {             //新しいリクエストオブジェクトを作成             FirstMessage myRequest = new FirstMessage();             myRequest.value = "The send time is: " + System.DateTime.Now.ToString();             //レスポンスを待たずに送信:             //SendRequestAsync("PEX.Webinar.FirstOperation", myRequest);             //送信して、20秒のタイムアウトでレスポンスを待機する:             FirstMessage myResponse=(FirstMessage) SendRequestSync("PEX.Webinar.FirstOperation", myRequest, 20);             return null;         }

FirstService:OnProcessInput

public override object OnProcessInput(object messageInput)         {             //新しいリクエストオブジェクトを作成             FirstMessage myRequest = new FirstMessage();             myRequest.value = "The send time is: " + System.DateTime.Now.ToString();             //レスポンスを待たずに送信:             //SendRequestAsync("PEX.Webinar.FirstOperation", myRequest);             //送信して、20秒のタイムアウトでレスポンスを待機する:             FirstMessage myResponse=(FirstMessage) SendRequestSync("PEX.Webinar.FirstOperation", myRequest, 20);             return null;         }
 

プロダクションのコンポーネントにコンパイルせずにメッセージを送信するために、管理ポータルで構成されたパラメーターを使用します。値は「RemoteSettings」構成パラメーター内に JSON 文字列として指定されています。

パラメーター

class FirstService : InterSystems.EnsLib.PEX.BusinessService     {          /// <summary>         /// ポータルから変更できるパラメーター         /// </summary>         public string TargetConfigName;      (...)

「TargetConfigName」に指定された値が null に設定されている場合、ビジネスサービスはどの宛先にもメッセージを送信しません。 この問題をできるだけ早期に検出するためには、1 つのオプションとして、コンポーネントが開始したときに、OnInit() 呼び出し内で TargetConfigName の値を検証することができます。

FirstService:OnInit

public override void OnInit()         {            //プロパティが正しく報告されることを検証            if (TargetConfigName==null )             {                 LOGWARNING("TargetConfigName is missing; assign it a value in RemoteSettings");             }else             {                 LOGINFO("TargetConfigname=" + TargetConfigName);             }         }

次に、OnProcessInput を、TargetConfigName の値を使用するように変更しましょう。

OnProcessInput

//送信して、20 秒のタイムアウトでレスポンスを待機: FirstMessage myResponse=(FirstMessage) SendRequestSync(TargetConfigName, myRequest, 20);

InterSystems IRIS での PEX ビジネスサービス {#Webinar:ImplementarIntegracionescon.NetoJava-BusinessServicePEXenInterSystemsIRIS}

管理ポータルで「+」をクリックして、プロダクションの定義にビジネスサービスタイプのコンポーネントを追加します。 

次に、(追加されたコンポーネントをクリックして)コンポーネントを構成し、右側の「Settings」(設定)タブを選択します。 

<th>
  値
</th>

<th>
  説明
</th>
<td>
  20
</td>

<td>
  関連するアダプターの OnTask() の実行と OnProcessInput() への呼び出し間の時間
</td>
<td>
  PEX.Webinar.FirstDemo.FirstService
</td>

<td>
  生成される .NET クラスの名前
</td>
<td>
  TargetConfigName=PEX.Webinar.FirstOperation
</td>

<td>
  param=value フォーマットによるパラメーターの &lt;newline> 区切りのリスト
</td>
<td>
  44444
</td>

<td>
  .NET ゲートウェイが構成されている TCP ポート
</td>
<td>
  C:\Dev\PEX\PEX.Webinar.FirstDemo\bin\Debug\ netstandard2.0\PEX.Webinar.FirstDemo.dll
</td>

<td>
  含める .DLL の場所。 これは、Visual Studio ビルドが .DLL を生成した場所です。
</td>
パラメーター
CallInterval
Remote Classname(リモートクラス名)
Remote Settings(リモート設定)
Gateway Port(ゲートウェイポート)
Gateway Extra CLASSPATH(ゲートウェイ追加クラスパス)

 

このビジネスサービスが有効になると、関連アダプター(Ens.InboundAdapter)のOnTask() の CallInterval が実行されます。 ここでは、OnTask は FirstService.OnProcessInput() を呼び出すだけです。 つまり、CallInterval と FirstService.OnProcessInput() ごとに、「TargetConfigName」で定義されたコンポーネントにメッセージが送信されます。 これはメッセージビューアーで確認可能です。

呼び出しの詳細が含まれます。

.NET ビジネスプロセス {#Webinar:ImplementarIntegracionescon.NetoJava-BusinessProcess.NET}

.NET の実装 {#Webinar:ImplementingIntegrationswith.NetorJava-.NETImplementation}

どのビジネスホストとも同様に、ビジネスプロセスにはコールバックの OnInit() と OnTearDown() メソッドがあります。 具体的に、ビジネスプロセスのメソッドは以下のとおりです。

<th>
  説明
</th>
<td>
  ビジネスプロセスに送信されるメッセージごとに実行されます。 プロセスの最初のアクションを実装する場所であり、他のコンポーネント(プロセスまたはオペレーション)に非同期配信を行います。
</td>
<td>
  非同期呼び出しの応答ごとに 1 回実行されます。 レスポンスをマージして結果を保存できます。
</td>
<td>
  ビジネスプロセスの実行の最後に 1 回実行されます。 プロセスの最終レスポンスメッセージが作成されます。
</td>
メソッド
OnRequest(message)
OnResponse
OnComplete

ビジネスプロセスの実行時間は長期(数時間から数日、非同期レスポンスを待機)になる可能性があることに注意しておくことが重要です。 これを可能にするために、IRIS フレームワークはプロセスの実行を中断して再開することができます。 プロセス中に維持したいすべての値は、IRIS が永続的に保存するクラスのプロパティに追加しておく必要があります。 [persistent] という表記で指示する必要があります。

この例では、最小限の実装が行われており、ビジネスプロセスは受信する PEX メッセージを宛先にルーティングします。

管理ポータルで変更可能な 2 つの変数が使用されています。

FirstProcess

class FirstProcess: InterSystems.EnsLib.PEX.BusinessProcess     {         //呼び出しのタイムアウト
          public string Timeout = "PT10S";

          public string TargetConfigName;

          public override void OnInit()
          {
              //プロパティが正しく入力されていることを確認
              if (TargetConfigName == null)
              {
                  LOGWARNING("Missing value for TargetConfigName; It must be assigned a value in RemoteSettings");
              }
              else
              {
                  LOGINFO("TargetConfigname=" + TargetConfigName);
              }
          }
</td>

 

メッセージを受信すると、TargetConfigName に非同期に送信されます。

FirstProces:OnRequest

public override object OnRequest(object request)         {             LOGINFO("OnRequest");             SendRequestAsync(TargetConfigName, (InterSystems.EnsLib.PEX.Message)request, true); //ResponseRequired=true             SetTimer(Timeout, "HasTimedOut");             return null;         }

OnResponse では、レスポンスをマージすることができます。

FirstProcess:OnResponse

public override object OnResponse(object request, object response, object callRequest,  object callResponse, string completionKey)        {            LOGINFO("OnResponse, CompletionKey=" + completionKey);            if (completionKey!= "HasTimedOut")            {                response = (FirstMessage)callResponse;            }            LOGINFO("Response:" + response.ToString());            return response;        }

プロセスの最後に、レスポンスが返されます。

FirstProcess:OnComplete

public override object OnComplete(object request, object response)       {           LOGINFO("OnComplete");           return response;       }

InterSystems IRIS での PEX ビジネスプロセス {#Webinar:ImplementarIntegracionescon.NetoJava-BusinessProcessPEXenIntersystemsIRIS}

EnsLib.PEX.BusinessProcess ビジネスプロセスを追加し、必要に応じて構成し、メッセージを BO に直接送信する代わりに新しいプロセスに送信するように「PEX.Webinar.FirstProcess」ビジネスサービスの TargetCongiNmae を変更します。 

コンポーネントの「Settings」(設定)は以下のように定義されます。

<th>
  値
</th>
<td>
  PEX.Webinar.FirstDemo.FirstProcess
</td>
<td>
  Timeout=PT20STargetConfigName=PEX.Webinar.FirstOperation
</td>
<td>
  44444
</td>
<td>
  C:\Dev\PEX\PEX.Webinar.FirstDemo\bin\Debug\netstandard2.0\PEX.Webinar.FirstDemo.dll
</td>
パラメーター
Remote Classname(リモートクラス名)
Remote Settings(リモート設定)
Gateway Port(ゲートウェイポート)
Gateway Extra Classpath(ゲートウェイ追加クラスパス)

トレースの結果は以下のようになります。

まとめ

PEX では、統合を .NET または Java で非常に流ちょうに実装でき、これらの言語の経験が豊富な開発者に対して InterSystems IRIS 相互運用性レイヤーの全能力と堅牢性を提供しています。

0
0 186
記事 Toshihiko Minamoto · 10月 26, 2023 4m read

問題

あわただしい臨床環境では迅速な意思決定が重要であるため、文書保管とシステムへのアクセスが合理化されていなければいくつもの障害を生み出します。 文書の保管ソリューションは存在しますが(FHIR など)、それらの文書内で特定の患者データに有意にアクセスして効果的に検索するのは、重大な課題となる可能性があります。

動機

AI により、文書の検索が非常に強力になりました。 ChromaLangchain のようなオープンソースツールを使用して、ベクトル埋め込みを保存して使用し、生成 AI API 全体でクエリを実行することで、ドキュメント上での質疑応答がかつてないほど簡単になっています。 より献身的に取り組む組織は、既存のドキュメントにインデックスを作成し、エンタープライズ用に微調整されたバージョンの GPT を構築しています。 GPT の現状に関する Andrej Karpathy の講演では、このトピックに関する素晴らしい概要が提供されています。

このプロジェクトは、医療関係者が文書を操作するあらゆるタッチポイントにおいて発生する摩擦を緩和する試みです。 医療関係者が情報を保管し、必要な情報を難なく検索できるように、入力と処理から保管と検索まで、IRIS FHIR と AI を活用しました。

ソリューション

医療関係者が音声メモを記録できるフルスタックのウェブアプリを構築しました。 これらのメモは、Open AI を使って文字起こしされ、要約されてから FHIR サーバーに保管されます。 保管されたドキュメントは、インデックス作成されてから、セマンティック検索で使用できるようになります。  

デモ動画

主な機能

  1. ウェブアプリ - 患者、観察、遭遇に関する診療情報を表示します。 これは Vue.js で構築されています。
  2. 音声データの文字起こし - Open AI Whisper API を使って、録音を正確なテキストに文字起こしします。
  3. テキストの要約 - 文字起こしされた内容を必要なフォーマットで要約してタイトルが付けられます。 症状、診断などの具体的なセクションなどです。 これは、text-da-vinci-003 を使った Open AI テキスト補完 API で行われます。
  4. ドキュメントの保管 - 要約されたドキュメントは、DocumentReference アーティファクトを使って FHIR に保管されます。
  5. セマンティックドキュメント検索 - 保管されたドキュメントはインデックス作成されて、チャンクとして Chroma に保管されます。 これは、Langchain を使用して検索スペースを制限してセマンティック検索に GPT トークンを控えめに使用するために使用されます。 現時点では、使用できるドキュメント数が少ないため、検索時にドキュメントを読み込んでいますが、 非同期的にバックグラウンドでインデックス作成するように変更することが可能です。
  6. ドキュメントのエクスポート - 最後に、ドキュメントを Google Docs に、その他のデータを Google Sheets にエクスポートするオプションがあります。 ユーザーは他の医療関係者や患者とのコラボレーションとやり取りを簡単に行えるように、OAuth を使って特定のアカウントにログインし、ドキュメントをエクスポートすることができます。

試してみましょう

次の GitHub リンクからプロジェクトリポジトリをクローンします: https://github.com/ikram-shah/iris-fhir-transcribe-summarize-export。 提供された指示に従って、プロジェクトをローカルマシン上にセットアップしてください。 期待される動作が得られない場合は、お知らせください。

ご意見とフィードバック

現在使用できる高度言語モデルと大量のデータを合わせることで、ヘルスケア分野の特に文書管理の領域に革命を起こす大きな可能性があります。 以下に、ご意見やフィードバックをお寄せください。 このプロジェクトの背後にある技術的な情報について、さらに多くの記事を投稿する予定です。

このプロジェクトに期待できると思われる場合は、Grand Prix コンテストでこのアプリに投票してください!

0
0 184
記事 Toshihiko Minamoto · 9月 28, 2023 22m read

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

私が作成した OpenAPI-Suite という最新のパッケージをご紹介します。これは、OpenAPI 仕様バージョン 3.0 から ObjectScript コードを生成するツールセットです。  簡単に言うと、これらのパッケージでは以下を行うことができます。

  • サーバーサイドクラスの生成。  ^%REST による生成コードに非常に似ていますが、バージョン 3.0 がサポートされていることに付加価値があります。
  • HTTP クライアントクラスの生成。
  • クライアントプロダクション(ビジネスサービス、ビジネスオペレーション、ビジネスプロセス、Ens.Request、Ens.Response)クラスの生成。
  • コードの生成とダウンロードまたはサーバーでの直接コンパイルを行う Web インターフェース。
  • バージョン 1.x からバージョン 3.0 への仕様の変換。
  • 概要

    OpenAPI Suite は多数のパッケージに分割されており、様々な開発者コミュニティライブラリや公開 REST サービスを使用しています。  以下の図では、開発されたすべてのパッケージと、使用されているライブラリと Web サービスを示しています。

    注意: 公開 REST サービスの使用に問題がある場合は、コンバーターとバリデーターサービスの Docker インスタンスを開始することができます。

    各パッケージの機能

    OpenAPI Suite は、メンテナンス、改善、および今後の拡張を行いやすくするために、様々なパッケージで設計されています。  パッケージごとに役割がありますので、  それを確認してみましょう!

    openapi-common-lib

    これには、他のパッケージのすべての共通コードが含まれています。  たとえば、openapi-client-genopenapi-server-gen は、OpenAPI 仕様の以下の入力を受け入れます。 

  • URL
  • ファイルパス
  • %Stream.Object 
  • %DynamicObject
  • YAML 形式
  • JSON 形式
  • OpenAPI バージョン 1.x、2.x、3.0.x
  • ただし、%DynamicObject 内の仕様 3.0.x のみを処理できます。  変換のコードはこのパッケージにあります。  また様々なユーティリティも含まれています。  

    swagger-converter-cli

    openapi-common-lib の依存関係です。  これは、OpenAPI バージョン 3.0 でバージョン 1.x または 2.x を変換するために公開 REST サービスの converter.swagger.io を使用する HTTP クライアントです。

    swagger-validator-cli

    これも openapi-common-lib の依存関係です。名前は「validator」となっていますが、仕様の検証に使用されるものではありません。  converter.swagger.io は、OpenAPI 仕様の構造を単純化できるように、「parse」サービスを提供しています。  例: 「nested object definition」の定義を作成し、それを「$ref」に置換します。  これにより、コード生成アルゴリズムで処理されるケース数が軽減されます。

    openapi-client-gen

    このパッケージは、開発者が REST サービスを使用しやすくするクライアントサイドのコード生成専用です。

    単純な HTTP クライアントまたはプロダクションクライアント(ビジネスサービス、プロセス、オペレーション、プロダクションクラス)が含まれます。  元々、OpenAPI 2.x をサポートするために作成されていましたが、バージョン 3.x をサポートするように完全にリファクタリングされました。

    openapi-server-gen

    これは openapi-client-gen とは逆に、サーバーサイドのコード生成専用です。  ^%REST が存在するため、仕様バージョン 2.0 ではなく、バージョン 3.0 サポートがこのパッケージのターゲットとなっています。  

    openapi-suite

    上記すべてのパッケージをひとまとめにし、以下を行う REST API を提供します。 

  • コードを生成し、IRIS インスタンスでコードをコンパイルします。
  • コンパイルせずにダウンロードのみのコードを生成します。
  • この REST API を使用し、OpenAPI Suite の機能を使用するための Web インターフェースも提供されています。

    ライブラリ

    以下に、この開発で利用した DC 上の既存のライブラリをいくつか紹介します。

    objectscript-openapi-definition

    OpenAPI 仕様からモデルクラスを生成する便利なライブラリです。  これはこのプロジェクトで非常に重要な要素であり、私自身も貢献しているライブラリです。

    ssl-client

    SSL 構成を作成できるようにします。  主に、HTTPS リクエストの「DefaultSSL」という名前の構成の作成に使用されています。  

    yaml-utils

    YAML 形式仕様の場合に、このライブラリは JSON 形式に変換するために使用されます。  このプロジェクトでは不可欠なライブラリです。  ちなみに、最初は openapi-client-gen バージョン 1 で YAML 仕様をテストするために開発されました。

    io-redirect

    これは私のライブラリの 1 つです。「write」をストリーム、ファイル、グローバル、または文字列変数にリダイレクトできます。  ログのトレースを維持するために、REST サービスで使用されています。  このコミュニティ記事からアイデアを得ました。

    IPM によるインストール

    このスイートをインストールするには、IPM(zpm)の使用が最適です。  多数のパッケージと依存関係があるため、IPM を使用するのが確実に便利と言えます。

    zpm "install openapi-suite"; optional; zpm "install swagger-ui"

     

    Docker によるインストール

    特別なことは何もありません。このプロジェクトは intersystems-iris-dev-template を使用しています。

    git clone git@github.com:lscalese/openapi-suite.git
    cd openapi-suite
    docker-compose up -d

    Iris の起動にエラーがある場合は、おそらく iris-main.log の権限の問題と思われます。

    以下を試してみてください。

    touch iris-main.log && chmod 777 iris-main.log

    注意: irisowner ユーザーに RW 権限を追加するだけで十分なはずです。

    使用方法

    OpenAPI-Suite には、コードを「生成してダウンロード」するか「生成してインストール」するための Web インターフェースが備わっています。  

    このインターフェースは http://localhost:52796/openapisuite/ui/index.cspで使用できます(*必要に応じて、使用しているポート番号に変更してください)。  

    非常に簡単で、フォームに入力するだけです。

  • Application package name: 生成されるクラスに使用されるパッケージの名前です。  既存でないパッケージ名である必要があります。
  • What do you want to generate?: 生成するものを HTTP Client、Client Production、または REST server から選択します。
  • Namespace: コードが生成されるネームスペースを選択します。  「Install On Server」(サーバーにインストール)をクリックした場合にのみ意味があり、そうでない場合はこのフィールドは無視されます。
  • Web Application Name: Web アプリケーションはオプションであり、「REST Server」の生成を選択した場合にのみ利用できます。  生成される REST ディスパッチクラスに関連する Web アプリケーションを作成しない場合は、空のままにします。
  • OpenAPI specification field: 仕様を指している URL を入力するか、仕様自体をコピー/貼り付けします(後者の場合、仕様は JSON 形式である必要があります)。
  • 「Download Only」(ダウンロードのみ)ボタンをクリックした場合、コードは XML ファイルで生成されて返され、クラスはサーバーから削除されます。  生成されるクラスを一時的に保存するために使用するネームスペースは、OpenAPI-Suite がインストールされているネームスペースです(Docker インストールを使用した場合のデフォルトは IRISAPP です)。  

    ただし、「Install On Server」(サーバーにインストール)ボタンをクリックした場合、コードは生成・コンパイルされ、サーバーは、コード生成/コンパイルのステータス付きの JSON メッセージとログを返します。

    デフォルトではこの機能は無効化されていますが、有効にするには IRIS ターミナルを開いて以下を実行してください。

    Set^openapisuite.config("web","enable-install-onserver") = 1

    OpenAPI-Suite REST API を詳しく見る

    CSP フォームは、http://localhost:52796/openapisuite にある REST サービスを使用します。

    swagger-ui http://localhost:52796/swagger-ui/index.html を開き、http://localhost:52796/openapisuite/_spec を詳しく見てみましょう。

    これは、Angular フレームワークを使用してより高度なフロントエンドアプリケーションを作成するための第一歩です。

    コードをプログラミングで生成する

    もちろん、UI の使用は必須ではありません。このセクションでは、コードをプログラミングで生成し、生成されたサービスを使用する方法について説明します。

    すべてのスニペットは、dc.openapi.suite.samples.PetStore クラスでも使用できます。

    HTTP クライアント

    Set features("simpleHttpClientOnly") = 1Set sc = ##class(dc.openapi.client.Spec).generateApp("petstoreclient", "https://petstore3.swagger.io/api/v3/openapi.json", .features)

     

    最初の引数は、クラスが生成されるパッケージであるため、有効なパッケージ名を渡すようにしましょう。  2 つ目の引数は、仕様を指す URL、ファイル名、ストリーム、または %DynamicObject です。  「features」は配列であり、現在以下のサブスクリプトのみを使用できます。 

    simpleHttpClientOnly: 1 である場合、単純な HTTP クライアントのみが生成されます。そうでない場合、プロダクションも生成されます(デフォルトの動作)。

    compile: 0 である場合、生成されたコードはコンパイルされません。  エクスポートの目的のみでコードを生成する場合に便利です。  デフォルトは、compile = 1 です。

    以下は、生成したばかりの HTTP クライアントで「addPet」サービスを使用する例です。

    Set messageRequest = ##class(petstoreclient.requests.addPet).%New()
    Set messageRequest.%ContentType = "application/json"Do messageRequest.PetNewObject().%JSONImport({"id":456,"name":"Mittens","photoUrls":["https://static.wikia.nocookie.net/disney/images/c/cb/Profile_-_Mittens.jpg/revision/latest?cb=20200709180903"],"status":"available"})
    

    Set httpClient = ##class(petstoreclient.HttpClient).%New("https://petstore3.swagger.io/api/v3","DefaultSSL") ; MessageResponse will be an instance of petstoreclient.responses.addPetSet sc = httpClient.addPet(messageRequest, .messageResponse) If$$$ISERR(sc) Do$SYSTEM.Status.DisplayError(sc) Quit sc

    Write !,"Http Status code : ", messageResponse.httpStatusCode,! Do messageResponse.Pet.%JSONExport()

     
    クリックして生成されたクラスを表示します。
    <div class="spoiler-content" style="">
      <pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Class</span> petstoreclient.HttpClient <span class="hljs-keyword">Extends</span> <span class="hljs-built_in">%RegisteredObject</span> [ ProcedureBlock ]
    

    {

    Parameter SERVER = "https://petstore3.swagger.io/api/v3";Parameter SSLCONFIGURATION = "DefaultSSL";Property HttpRequest [ InitialExpression = {##class(%Net.HttpRequest).%New()} ];Property SSLConfiguration As%String [ InitialExpression = {..#SSLCONFIGURATION} ];Property Server As%String [ InitialExpression = {..#SERVER} ];Property URLComponents [ MultiDimensional ]; Method %OnNew(Server As%String, SSLConfiguration As%String) As%Status { Set:$Data(Server) ..Server = Server Set:$Data(SSLConfiguration) ..SSLConfiguration = SSLConfiguration Quit..InitializeHttpRequestObject() }

    Method InitializeHttpRequestObject() As%Status { Set..HttpRequest = ##class(%Net.HttpRequest).%New() Do##class(%Net.URLParser).Decompose(..Server, .components) Set:$Data(components("host"), host) ..HttpRequest.Server = host Set:$Data(components("port"), port) ..HttpRequest.Port = port Set:$$$LOWER($Get(components("scheme")))="https"..HttpRequest.Https = $$$YES, ..HttpRequest.SSLConfiguration = ..SSLConfigurationMerge:$Data(components) ..URLComponents = components Quit$$$OK }

    /// Implement operationId : addPet/// post /pet Method addPet(requestMessage As petstoreclient.requests.addPet, Output responseMessage As petstoreclient.responses.addPet = {##class(petstoreclient.responses.addPet).%New()}) As%Status { Set sc = $$$OK$$$QuitOnError(requestMessage.LoadHttpRequestObject(..HttpRequest)) $$$QuitOnError(..HttpRequest.Send("POST", $Get(..URLComponents("path")) _ requestMessage.%URL)) $$$QuitOnError(responseMessage.LoadFromResponse(..HttpRequest.HttpResponse, "addPet")) Quit sc } ... }

      <p>
         
      </p>
      
      <pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Class</span> petstoreclient.requests.addPet <span class="hljs-keyword">Extends</span> <span class="hljs-built_in">%RegisteredObject</span> [ ProcedureBlock ]
    

    {

    Parameter METHOD = "post";Parameter URL = "/pet";Property%ConsumeAs%String;Property%ContentTypeAs%String;Property%URLAs%String [ InitialExpression = {..#URL} ];/// Use this property for body content with content-type = application/json.
    /// Use this property for body content with content-type = application/xml.
    /// Use this property for body content with content-type = application/x-www-form-urlencoded.Property Pet As petstoreclient.model.Pet;/// Load %Net.HttpRequest with this property object. Method LoadHttpRequestObject(ByRef httpRequest As%Net.HttpRequest) As%Status { Set sc = $$$OKSet httpRequest.ContentType = ..%ContentTypeDo httpRequest.SetHeader("accept", ..%Consume) If$Piece($$$LOWER(..%ContentType),";",1) = "application/json"Do..Pet.%JSONExportToStream(httpRequest.EntityBody) If$Piece($$$LOWER(..%ContentType),";",1) = "application/xml"Do..Pet.XMLExportToStream(httpRequest.EntityBody) If$Piece($$$LOWER(..%ContentType),";",1) = "application/x-www-form-urlencoded" { ; To implement. この場合、コードの生成はまだありません。$$$ThrowStatus($$$ERROR($$$NotImplemented)) } Quit sc }

    }

      <p>
         
      </p>
      
      <pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Class</span> petstoreclient.responses.addPet <span class="hljs-keyword">Extends</span> petstoreclient.responses.GenericResponse [ ProcedureBlock ]
    

    {

    /// http status code = 200 content-type = application/xml/// http status code = 200 content-type = application/json/// Property Pet As petstoreclient.model.Pet;/// Implement operationId : addPet/// post /pet Method LoadFromResponse(httpResponse As%Net.HttpResponse, caller As%String = "") As%Status { Set sc = $$$OKDo##super(httpResponse, caller) If$$$LOWER($Piece(httpResponse.ContentType,";",1))="application/xml",httpResponse.StatusCode = "200" { $$$ThrowStatus($$$ERROR($$$NotImplemented)) } If$$$LOWER($Piece(httpResponse.ContentType,";",1))="application/json",httpResponse.StatusCode = "200" { Set..Pet = ##class(petstoreclient.model.Pet).%New() Do..Pet.%JSONImport(httpResponse.Data) Return sc } Quit sc }

    }

      <p>
         
      </p>
    </div>
    

     

    HTTP クライアントのプロダクション

    Set sc = ##class(dc.openapi.client.Spec).generateApp("petstoreproduction", "https://petstore3.swagger.io/api/v3/openapi.json")

    最初の引数は、単純な HTTP クライアントのコード生成をテストする場合のパッケージ名であるため、クライアントプロファクションの場合は必ず別のパッケージ名を使用してください。  2 つ目と 3 つ目も HTTP クライアントと同じルールが適用されます。

    テストする前に、以下のコマンドを使用して、管理ポータルからプロダクションを起動してください。

    Do##class(Ens.Director).StartProduction("petstoreproduction.Production")

    以下は、「addPet」サービスを使用する例ですが、今回は生成されたプロダクションを使用します。

    Set messageRequest = ##class(petstoreproduction.requests.addPet).%New()
    Set messageRequest.%ContentType = "application/json"Do messageRequest.PetNewObject().%JSONImport({"id":123,"name":"Kitty Galore","photoUrls":["https://www.tippett.com/wp-content/uploads/2017/01/ca2DC049.130.1264.jpg"],"status":"pending"})
    ; MessageResponse will be an instance of petstoreclient.responses.addPetSet sc = ##class(petstoreproduction.Utils).invokeHostSync("petstoreproduction.bp.SyncProcess", messageRequest, "petstoreproduction.bs.ProxyService", , .messageResponse)
    Write !, "Take a look in visual trace (management portal)"If$$$ISERR(sc) Do$SYSTEM.Status.DisplayError(sc)
    Write !,"Http Status code : ", messageResponse.httpStatusCode,!
    Do messageResponse.Pet.%JSONExport()

    次に、視覚的なトレースを開いて詳細を確認します。 

    packages モデル、リクエスト、およびレスポンスに生成されたクラスは、単純な HTTP クライアント用に生成されるコードと非常によく似ています。  パッケージリクエストのクラスは Ens.Request を継承し、パッケージレスポンスのクラスは Ens.Response を継承します。  ビジネスオペレーションのデフォルトの実装は非常に単純です。以下のスニペットをご覧ください。 

    Class petstoreproduction.bo.Operation Extends Ens.BusinessOperation [ ProcedureBlock ]
    {
    
    Parameter ADAPTER = "EnsLib.HTTP.OutboundAdapter";Property Adapter As EnsLib.HTTP.OutboundAdapter;/// Implement operationId : addPet/// post /pet
    Method addPet(requestMessage As petstoreproduction.requests.addPet, Output responseMessage As petstoreproduction.responses.addPet) As%Status
    {
        Set sc = $$$OK, pHttpRequestIn = ##class(%Net.HttpRequest).%New(), responseMessage = ##class(petstoreproduction.responses.addPet).%New()
        $$$QuitOnError(requestMessage.LoadHttpRequestObject(pHttpRequestIn))
        $$$QuitOnError(..Adapter.SendFormDataArray(.pHttpResponse, "post", pHttpRequestIn, , , ..Adapter.URL_requestMessage.%URL))
        $$$QuitOnError(responseMessage.LoadFromResponse(pHttpResponse, "addPet"))
        Quit sc
    }
    ...
    }
    }

     

    HTTP サーバーサイド REST アプリケーション

    Set sc = ##class(dc.openapi.server.ServerAppGenerator).Generate("petstoreserver", "https://petstore3.swagger.io/api/v3/openapi.json", "/petstore/api")

    最初の引数は、クラスを生成するパッケージ名です。  2 つ目は HTTP クライアントと同じルールが適用されます。  3 つ目の引数は必須ではありませんが、使用されている場合、Web アプリケーションが指定された名前で作成されます(有効な Web アプリケーション名を指定することに注意してください)。

    クラス petstoreserver.disp(ディスパッチ %CSP.REST クラス)は、^%REST が生成するコードに似ており、リクエストを受け入れるか拒否する多数のチェックを実行し、petstoreserver.impl で関連するサービス ClassMethod 実装を呼び出します。  主な違いは、実装メソッドに渡される引数で、これは petstoreserver.requests オブジェクトです。 例:

    Class petstoreserver.disp Extends%CSP.REST [ ProcedureBlock ]
    {
    

    Parameter CHARSET = "utf-8";Parameter CONVERTINPUTSTREAM = 1;Parameter IgnoreWrites = 1;Parameter SpecificationClass = "petstoreserver.Spec";/// Process request post /petClassMethod addPet() As%Status { Set sc = $$$OKTry{ Set acceptedMedia = $ListFromString("application/json,application/xml,application/x-www-form-urlencoded") If '$ListFind(acceptedMedia,$$$LOWER(%request.ContentType)) { Do##class(%REST.Impl).%ReportRESTError(..#HTTP415UNSUPPORTEDMEDIATYPE,$$$ERROR($$$RESTContentType,%request.ContentType)) Quit } Do##class(%REST.Impl).%SetContentType($Get(%request.CgiEnvs("HTTP_ACCEPT"))) If '##class(%REST.Impl).%CheckAccepts("application/xml,application/json") Do##class(%REST.Impl).%ReportRESTError(..#HTTP406NOTACCEPTABLE,$$$ERROR($$$RESTBadAccepts)) QuitIf '$isobject(%request.Content) Do##class(%REST.Impl).%ReportRESTError(..#HTTP400BADREQUEST,$$$ERROR($$$RESTRequired,"body")) QuitSet requestMessage = ##class(petstoreserver.requests.addPet).%New() Do requestMessage.LoadFromRequest(%request) Set scValidateRequest = requestMessage.RequestValidate() If$$$ISERR(scValidateRequest) Do##class(%REST.Impl).%ReportRESTError(..#HTTP400BADREQUEST,$$$ERROR(5001,"Invalid requestMessage object.")) QuitSet response = ##class(petstoreserver.impl).addPet(requestMessage) Do##class(petstoreserver.impl).%WriteResponse(response) } Catch(ex) { Do##class(%REST.Impl).%ReportRESTError(..#HTTP500INTERNALSERVERERROR,ex.AsStatus(),$parameter("petstoreserver.impl","ExposeServerExceptions")) } Quit sc } ... }

    ご覧のとおり、dispatch クラスは実装メソッドを呼び出す前に「LoadFromRequest」と「RequestValidate」を呼び出しています。  これらのメソッドにはデフォルトの実装がありますが、コードジェネレーターはすべてのケースに対応できません。  現時点では、「query」、「headers」、「path」、およびコンテンツタイプが「application/json」、「application/octet-stream」、または「multipart/form-data」である body で最も一般的なケースがパラメーターとして自動的に処理されます。  開発者は、必要に応じて実装をチェック/完了する必要があります(未対応のケースについては、デフォルトでは、コードジェネレーターは $$$ThrowStatus($$$ERROR($$$NotImplemented)) を設定します)。

     
    リクエストクラスの例:
    Class petstoreserver.requests.addPet Extends%RegisteredObject [ ProcedureBlock ]
    {
    

    Parameter METHOD = "post";Parameter URL = "/pet";Property%ConsumeAs%String;Property%ContentTypeAs%String;Property%URLAs%String [ InitialExpression = {..#URL} ];/// Use this property for body content with content-type = application/json.
    /// Use this property for body content with content-type = application/xml.
    /// Use this property for body content with content-type = application/x-www-form-urlencoded.Property Pet As petstoreserver.model.Pet;/// Load object properties from %CSP.Request object. Method LoadFromRequest(request As%CSP.Request = {%request}) As%Status { Set sc = $$$OKSet ..%ContentType = $Piece(request.ContentType, ";", 1) If ..%ContentType = "application/json"{ Do..PetNewObject().%JSONImport(request.Content) } If ..%ContentType = "application/xml" { ; To implement. There is no code generation yet for this case.$$$ThrowStatus($$$ERROR($$$NotImplemented)) } If ..%ContentType = "application/x-www-form-urlencoded" { ; To implement. There is no code generation yet for this case.$$$ThrowStatus($$$ERROR($$$NotImplemented)) } Quit sc }

    /// Load object properties from %CSP.Request object. Method RequestValidate() As%Status { Set sc = $$$OK$$$QuitOnError(..%ValidateObject()) If ''$ListFind($ListFromString("application/json,application/xml,application/x-www-form-urlencoded"), ..%ContentType) { Quit:..Pet=""$$$ERROR(5659, "Pet") } If$IsObject(..Pet) $$$QuitOnError(..Pet.%ValidateObject()) Quit sc }

    }

    <p>
       
    </p>
    

     

    ^%REST の使用方法と同じように、「petstoreserver.impl」クラスには、サービスに関連したすべてのメソッドが含まれており、開発者が実装する必要があります。 

    Class petstoreserver.impl Extends%REST.Impl [ ProcedureBlock ]
    {
    
    Parameter ExposeServerExceptions = 1;/// Service implemntation for post /petClassMethod addPet(messageRequest As petstoreserver.requests.addPet) As%Status
    {
        ; Implement your service here.; Return {}$$$ThrowStatus($$$ERROR($$$NotImplemented))
    }
    
    ...
    }

     

    生成されたパッケージの短い説明

      <td>
        タイプ
      </td>
      
      <td>
        説明
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreclient.model petstoreproduction.model
      </td>
      
      <td>
        クライアントサイドとサーバーサイド
      </td>
      
      <td>
        すべてのモデルが含まれます。  これらのクラスは、JSON から簡単にオブジェクトを読み込めるように %JSON.Adaptor を拡張します。   プロダクションが生成されると、これらのクラスは %Persistent も拡張します。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreclient.requests   petstoreproduction.requests
      </td>
      
      <td>
        クライアントサイドとサーバーサイド
      </td>
      
      <td>
        %Net.HttpRequest を簡単に初期化するために使用されるオブジェクト。  仕様にはオペレーションごとのクラスが定義されています。プロダクションが生成される場合、これらのクラスは Ens.Request を拡張します。 注意: このクラスの実装は、生成対象がサーバーサイドであるかクライアントサービスであるかによって異なります。  クライアントサイドの場合、すべてのクラスには「LoadHttpRequestObject」メソッドが含まれるため、このクラスプロパティから「%Net.HttpRequest」を読み込むことができます。 クラスがサーバーサイドを対象に生成される場合、「%request」オブジェクトからインスタンスを読み込むために、各クラスに「LoadFromRequest」メソッドが含まれています。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreclient.responses petstoreproduction.responses
      </td>
      
      <td>
        クライアントサイドとサーバーサイド
      </td>
      
      <td>
        petstoreclient.requests の 逆です。  %Net.HttpRequest のレスポンスを処理できます。プロダクションが生成される場合、これらのクラスは Ens.Response を拡張します。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreclient.HttpClient
      </td>
      
      <td>
        クライアントサイド
      </td>
      
      <td>
        HTTP リクエストを実行するためのすべてのメソッドが含まれます。OpenAPI 仕様で定義されるオペレーションごとに 1 つのメソッドがあります。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreproduction. bo.Operation
      </td>
      
      <td>
        クライアントサイド
      </td>
      
      <td>
        オペレーションクラスには、OpenAPI 仕様で定義されたオペレーションごとに 1 つのメソッドがあります。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreproduction.bp
      </td>
      
      <td>
        クライアントサイド
      </td>
      
      <td>
        同期と非同期の 2 つのデフォルトのビジネスプロセスが定義されています。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreproduction.bs
      </td>
      
      <td>
        クライアントサイド
      </td>
      
      <td>
        実装するすべての空のビジネスサービスが含まれます。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreproduction.Production
      </td>
      
      <td>
        クライアントサイド
      </td>
      
      <td>
        プロダクション構成の設定。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreserver.disp
      </td>
      
      <td>
        サーバーサイド
      </td>
      
      <td>
        クラス dispatch %CSP.REST
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreserver.Spec
      </td>
      
      <td>
        サーバーサイド
      </td>
      
      <td>
        このクラスには、XData ブロックに OpenAPI 仕様が含まれています。
      </td>
    </tr>
    
    <tr>
      <td>
        petstoreserver.impl
      </td>
      
      <td>
        サーバーサイド
      </td>
      
      <td>
        これには、OpenAPI 仕様で定義されたオペレーションに関連するすべての空のメソッドが含まれています。  これが、開発者がサービスを実装する必要のあるクラス(%REST.Impl を拡張)です。
      </td>
    </tr>
    
    パケージ名 / クラス名

    開発ステータス

    OpenAPI-Suite はまだ非常に未熟な製品であり、さらに多くのテストを実施した上での改善が必要です。  OpenAPI 3 のサポートは部分的であり、さらに多くの機能がサポートされる可能性があります。 

    テストは公開されている仕様 https://petstore3.swagger.io/api/v3/openapi.json と比較的に単純な 2 つの仕様を使って実施されました。  もうちろん、すべてのケースに対応するには不十分です。  仕様を共有していただければ、喜んでテストに使用させていただきます。

    このプロジェクトの基盤は十分であり、AsyncAPI をサポートするように拡張するなど、簡単に進化させることができると考えています。

    お気軽にフィードバックをお寄せください。

    このアプリケーションをご利用いただき、開発者ツールコンテストで支援していただければ幸いです。

    お読みいただきありがとうございました。

    0
    0 132
    記事 Toshihiko Minamoto · 8月 7, 2023 7m read

    この記事では、.Net/Java ゲートウェイを簡単にコンテナ化する方法を説明します。

    この例では、Apache Kafka との統合を開発します。

    Java/.Net と相互運用するために、PEX を使用しています。

    アーキテクチャ

    このソリューションは完全に docker で実行し、以下のように構成されます。

    Java ゲートウェイ

    まず、メッセージを Kafka に送信する Java オペレーションを開発しましょう。 このコードはお好きな IDE で書くことができ、こちらのようになります。

    要約すると:

    • 新しい PEX ビジネスオペレーションを開発するには、抽象型の com.intersystems.enslib.pex.BusinessOperation クラスを実装する必要があります。
    • public プロパティはビジネスホスト設定です。
    • OnInit メソッドは Kafka への接続を初期化し、InterSystems IRIS へのポインターを取得するために使用されます。
    • OnTearDown は、(プロセスのシャットダウン時に)Kafka から切断するために使用されます。
    • OnMessagedc.KafkaRequest メッセージを受け取って、Kafka に送信します。

    では、これを Docker にパックしましょう!

    これがこの例の dockerfile です。

    FROM eclipse-temurin:8-jre-alpine AS builder
    
    ARG APP_HOME=/tmp/app
    
    COPY src $APP_HOME/src
    
    COPY --from=intersystemscommunity/jgw:latest /jgw/*.jar $APP_HOME/jgw/
    
    WORKDIR $APP_HOME/jar/
    ADD https://repo1.maven.org/maven2/org/apache/kafka/kafka-clients/2.5.0/kafka-clients-2.5.0.jar .
    ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar .
    ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar .
    ADD https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar .
    
    WORKDIR $APP_HOME/src
    
    RUN javac -classpath $APP_HOME/jar/*:$APP_HOME/jgw/* dc/rmq/KafkaOperation.java && \
        jar -cvf $APP_HOME/jar/KafkaOperation.jar dc/rmq/KafkaOperation.class
    
    FROM intersystemscommunity/jgw:latest
    
    COPY --from=builder /tmp/app/jar/*.jar $GWDIR/
    

    1 行ずつ見ながら、ここに何が起きているのかを確認しましょう(マルチステージ docker ビルドを理解していることが前提です)。

    FROM eclipse-temurin:8-jre-alpine AS builder
    

    最初のイメージは JDK 8 です(openjdk:8 イメージは廃止されたことに注意してください。代わりに推奨されているものを使用します)。

    ARG APP_HOME=/tmp/app
    COPY src $APP_HOME/src
    

    /src フォルダから /tmp/app フォルダにソースをコピーしています。

    COPY --from=intersystemscommunity/jgw:latest /jgw/*.jar $APP_HOME/jgw/

    Java ゲートウェイソースを /tmp/app/jgw フォルダにコピーしています。

    WORKDIR $APP_HOME/jar/
    ADD https://repo1.maven.org/maven2/org/apache/kafka/kafka-clients/2.5.0/kafka-clients-2.5.0.jar .
    ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar .
    ADD https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar .
    ADD https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar .
    
    WORKDIR $APP_HOME/src
    
    RUN javac -classpath $APP_HOME/jar/*:$APP_HOME/jgw/* dc/rmq/KafkaOperation.java && \
        jar -cvf $APP_HOME/jar/KafkaOperation.jar dc/rmq/KafkaOperation.class
    

    これですべての依存関係が追加され、jar ファイルのコンパイルに javac/jar が呼び出されます。 実際のプロジェクトでは、Maven または Gradle の使用をお勧めします。

    FROM intersystemscommunity/jgw:latest
    
    COPY --from=builder /tmp/app/jar/*.jar $GWDIR/
    

    そして最後に、jar がベース jgw イメージにコピーされます(ベースイメージは、ゲートウェイと関連タスクの開始も処理します)。

    .Net ゲートウェイ

    次は、Kafka からメッセージを受け取る .Net サービスです。 このコードはお好きな IDE で書くことができ、こちらのようになります。

    要約すると:

    • 新しい PEX ビジネスサービスを開発するには、抽象型の InterSystems.EnsLib.PEX.BusinessService クラスを実装する必要があります。
    • public プロパティはビジネスホスト設定です。
    • OnInit メソッドは Kafka への接続を初期化し、トピックを購読し、InterSystems IRIS へのポインターを取得するために使用されます。
    • OnTearDown は、(プロセスのシャットダウン時に)Kafka から切断するために使用されます。
    • OnMessage は Kafka からのメッセージを入力として使用し、他の相互運用性ホストに Ens.StringContainer メッセージを送信します。

    では、これを Docker にパックしましょう!

    これがこの例の dockerfile です。

    FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build
    
    ENV ISC_PACKAGE_INSTALLDIR /usr/irissys
    ENV GWLIBDIR lib
    ENV ISC_LIBDIR ${ISC_PACKAGE_INSTALLDIR}/dev/dotnet/bin/Core21
    
    WORKDIR /source
    COPY --from=store/intersystems/iris-community:2020.2.0.211.0 $ISC_LIBDIR/*.nupkg $GWLIBDIR/
    
    # copy csproj and restore as distinct layers
    COPY *.csproj ./
    RUN dotnet restore
    
    # copy and publish app and libraries
    COPY . .
    RUN dotnet publish -c release -o /app
    
    # final stage/image
    FROM mcr.microsoft.com/dotnet/core/runtime:2.1
    WORKDIR /app
    COPY --from=build /app ./
    
    # Configs to start the Gateway Server
    RUN cp KafkaConsumer.runtimeconfig.json IRISGatewayCore21.runtimeconfig.json && \
        cp KafkaConsumer.deps.json IRISGatewayCore21.deps.json
    
    ENV PORT 55556
    
    CMD dotnet IRISGatewayCore21.dll $PORT 0.0.0.0
    

    1 行ずつ見ていきましょう。

    FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build
    

    このアプリの構築には、完全な .Net Core 2.1 SDK を使用します。

    ENV ISC_PACKAGE_INSTALLDIR /usr/irissys
    ENV GWLIBDIR lib
    ENV ISC_LIBDIR ${ISC_PACKAGE_INSTALLDIR}/dev/dotnet/bin/Core21
    
    WORKDIR /source
    COPY --from=store/intersystems/iris-community:2020.2.0.211.0 $ISC_LIBDIR/*.nupkg $GWLIBDIR/
    

    正式な InterSystems Docker イメージから .Net Gateway NuGets をビルダーイメージにコピーします。

    # copy csproj and restore as distinct layers
    COPY *.csproj ./
    RUN dotnet restore
    
    # copy and publish app and libraries
    COPY . .
    RUN dotnet publish -c release -o /app
    

    ライブラリを構築します。

    # final stage/image
    FROM mcr.microsoft.com/dotnet/core/runtime:2.1
    WORKDIR /app
    COPY --from=build /app ./
    

    ライブラリ dll を、実際に実行する最終コンテナにコピーします。

    # Configs to start the Gateway Server
    RUN cp KafkaConsumer.runtimeconfig.json IRISGatewayCore21.runtimeconfig.json && \
        cp KafkaConsumer.deps.json IRISGatewayCore21.deps.json
    

    現在、.Net ゲートウェイは起動時にすべての依存関係を読み込む必要があるため、考えられるすべての依存関係を認識するようにしています。

    ENV PORT 55556
    
    CMD dotnet IRISGatewayCore21.dll $PORT 0.0.0.0
    

    すべてのインターフェースでリッスンするポート 55556 でゲートウェイを開始します。

    以上です!

    こちらは、すべてをまとめて実行する完全な docker-compose です(Kafka とメッセージを見るための Kafka UI も含まれています)。

    このデモを実行するには、以下を行う必要があります。

    1. インストール:
    2. 実行:
    git clone https://github.com/intersystems-community/pex-demo.git cd pex-demo docker-compose pull docker-compose up -d
    

     

    注意事項: Java ゲートウェイと .Net ゲートウェイライブラリは、InterSystems IRIS クライアントと同じバージョンのものである必要があります。

    0
    0 189
    記事 Toshihiko Minamoto · 7月 13, 2023 5m read

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

    ご存知のように、InterSystems IRIS インターオペラビリティソリューションには、プロダクション、ビジネスルール、ビジネスプロセス、データ変換、レコードマッパーなどの様々なエレメントが含まれています。 また、UI ツールを使用してこれらの要素を作成し、変更することもあります。  もちろん、UI ツールで行った変更をソース管理する便利で堅牢な方法も必要です。

    長い間、これは手動(クラス、エレメント、グローバルなどのエクスポート)か面倒な設定作業手順によって行われてきました。そのため、ソース管理 UI の自動化で節約された時間は、設定のセットアップとメンテナンスの時間で相殺されていました。

    現在では、この問題はなくなりました。 パッケージファースト開発と @Timothy Leavittgit-source-control という IPM パッケージの使用という 2 つのアプローチによる結果です。

    詳細は以下のとおりです!

    免責事項: これは、インターオペラビリティのプロダクションのエレメントがリポジトリ内のファイルである場合の、クライアント側の開発アプローチに関連しています。

    よって、ソリューションは非常に単純であるため、この記事は長くありません。

    Docker で開発しており、IRIS を使って開発環境の Docker イメージをビルドしたら、ソリューションを IPM モジュールとして読み込んでいるとします。 これは、「パッケージファースト」開発と呼ばれ、関連する動画や記事が存在する手法です。 基本的には、開発環境の Docker イメージを IRIS でビルドすると、クライアントのサーバーにデプロイされるときに、ソリューションがパッケージとして読み込まれるという考え方になります。

    ソリューションのパッケージファースト開発環境を作るには、module.xml をリポジトリに追加し、そのすべての要素を記述して、Docker イメージのビルドフェーズで「zpm load "repository/folder"」コマンドを呼び出します。

    この考え方を、サンプルテンプレートの IRIS Interoperability template とそれに使用する module.xml を使って示しましょう。 パッケージは、Docker ビルド中に以下のように読み込まれています。

    zpm "load /home/irisowner/irisdev/ -v":1:1

    ソース 

    パッケージソース管理を読み込む前に配置された以下の 2 行を見てください。 これにより、ソース管理はパッケージ内のすべての相互運用性要素に対して自動的に動作し始め、適切なフォルダに適切な形式でエクスポートされます。

    zpm "install git-source-control"do##class(%Studio.SourceControl.Interface).SourceControlClassSet("SourceControl.Git.Extension")

    ソース

    仕組み

    最近、git-source-control アプリは、開発モードで読み込まれるソース管理用の IPM パッケージをサポートするようになりました。 エクスポートするフォルダを読み取り、module.xml からソースの構造をインポートします。 詳細は、@Timothy Leavitt が説明できます。

    ターミナルで、環境がビルドされた後の IPM モジュールのリストを確認すると、読み込まれたモジュールが実際に開発モードになっているのが分かります。

    USER>zpm=============================================================================
    || Welcome to the Package Manager Shell (ZPM).                             ||
    || Enter q/quit to exit the shell. Enter ?/help to view available commands ||
    =============================================================================
    zpm:USER>list
    git-source-control      2.1.0
    interoperability-sample 0.1.2 (DeveloperMode)
    sslclient               1.0.1
    zpm:USER>

    では試してみましょう。 

    このリポジトリをクローンし、VSCode で開いてイメージをビルドしました。 以下では、相互運用性 UI とソース管理をテストしています。 UI に変更を加えるとすぐに、ソースと差分に表示されます。

    できました! それだけです! 

    まとめると、プロジェクトで相互運用性 UI 要素のソース管理を行うには、以下を行います。

    1. Docker イメージをビルド中に、iris.script に 2 行を追加します。
    zpm "install git-source-control"do##class(%Studio.SourceControl.Interface).SourceControlClassSet("SourceControl.Git.Extension")

    その後、以下のようにして、ソリューションをモジュールとして読み込みます。

    zpm "load /home/irisowner/irisdev/ -v":1:1
    1. または、Interoperability template からリポジトリを作成して新規に始めることもできます。

    お読みいただきありがとうございました! コメントやフィードバックをお待ちしています!

    0
    0 247
    記事 Mihoko Iijima · 6月 13, 2023 1m read

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

    注意:本番環境では実行しないでください。テスト環境でご利用ください。

    開発時にプロダクションに残っているキューを一括でクリアしたり、プロダクションに関連した一次的な情報をすべて消去したい場合、以下メソッドを利用して実行中のプロダクション情報をリセットできます。

    set$namespace="プロダクションのあるネームスペース名指定"do##class(Ens.Director).CleanProduction()

    ドキュメント:ネームスペースでのプロダクションのリセット

    プロダクション全体ではなく、一部コンポーネントの実行中データをリセットする場合は、アダプタの ClearAllAppData() を使用します。
    引数にはプロダクションに登録している構成名を指定してください。

    例)SQLインバウンドアダプタが保持している永続値をリセットする

    do##class(EnsLib.SQL.InboundAdapter).ClearAllAppData("構成名称")

    ドキュメント:受信アダプタで以前に処理された行のリセット

    例)FTPインバウンドアダプタが処理したファイルの情報をリセットする

    do##class(EnsLib.FTP.InboundAdapter).ClearAllAppData("構成名称")
    0
    0 140
    記事 Mihoko Iijima · 6月 2, 2023 6m read

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

    この記事では、ワークフローコンポーネントを使ってみよう!~使用手順解説~ でご紹介したユーザ操作画面(ユーザポータル)を任意のWebアプリに変更する際に便利な REST API の使用方法をご紹介します。

    ワークフロー用 REST APIですが、開発者コミュニティのサンプル公開ページ:Open Exchange に公開されているAPIでどなたでも自由にご利用いただけます。

    Open Exchangeの検索ボックスに「Workflow rest」と入力すると出てきます。EnsembleWorkflow が対象のサンプルです。

    ちなみに、2023年6月2日時点で724のアプリケーションが公開されているようです👀

    0
    0 376
    記事 Mihoko Iijima · 6月 1, 2023 21m read

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

    この記事では、システム連携の自動的な流れの中にユーザからの指示を介入できる「ワークフローコンポーネント」のサンプル でご紹介した内容を、お手元のIRIS、IRIS for Healthを利用して体験いただくための手順を解説します。

    なお、ワークフローコンポーネントでどんなことができるのか?の概要説明については、ウェビナーをご参照ください。

    A.事前準備

    1) InterSystems IRIS または、IRIS for Healthのインストール環境をご用意ください。

    まだインストール環境がない場合は、コミュニティエディション(コンテナ版かキット版)をご利用ください。

    0
    0 390