TT Lab
はじめる
学ぶ 学習パス コース

EAI 中間層をつくる

取引コードで行き先を決めるルーター

TT Labで続きを見る

目標

業務部門のインターフェース一覧をルーティング表(データ)に整理し、電文ヘッダーだけを見て宛先を決めるルーターを、ルールの優先順位(ORG > EXACT > 長いPREFIX > NONE)どおりに作ります。

なぜ重要なのか

ハブのルーティングが間違うと、エラーになる代わりに電文が黙って別のシステムへ行ってしまいます。そこでルールをコードではなく表に置き、重なったときにどれが勝つかを行の順序ではなくコードで明示し、どのルールに一致したかを監査ログに残します。ルーティングできないものを握りつぶさずE101レスポンスで返すのも、ハブの責任です。握りつぶすと、送ったチャネルはタイムアウトまで待ちます。

ステップ

  1. /opt/lab/fixtures/eaimw/route/interfaces.csvと/opt/lab/fixtures/eaimw/route/ROUTING.mdの2節を読み、/root/eaimw/route/routes.csvを作成してください。見出し行はtx_code,target,mode,timeout_msです。状態が운영(韓国語で「運用」を意味する語です)の行だけを対象にし、同じ取引コードはバージョン(整数)が最大の行を1つだけ残します。取引コードと宛先は空白を除いて大文字にし、modeはSYNC/ASYNC、timeout_msは秒×1000の整数にします。プレフィックスルール(CD*)もそのまま載せ、tx_codeのバイト順(LC_ALL=C sort)で並べ替えます。
  2. /root/eaimw/route/router.pyを作成してください。python3 router.py --routes <표> lookup <거래코드>(プレースホルダーは表と取引コードです)が、完全一致の行を探してJSON1行{"target": ..., "rule": "EXACT", "mode": ..., "timeout_ms": 정수}(プレースホルダーは整数です)を出力し、0で終わります。ない場合は{"target": null, "rule": "NONE"}と終了コード3で終わります。表にプレフィックス行があっても落ちてはいけません。--routesを省略すると/root/eaimw/route/routes.csvを使います。
  3. プレフィックスルールを追加してください。取引コードがCD*のCDで始まるなら、ruleはPREFIXです。完全一致がプレフィックスより、長いプレフィックスが短いプレフィックスより優先されます。表の行の順序とは無関係でなければなりません。
  4. 機関ルールを追加してください。lookup <거래코드> --rcv-org <기관>(プレースホルダーは取引コードと機関です)で機関が100でなければ、取引コードに関係なく{"target": "FEP", "rule": "ORG"}を出力して0で終わります。--rcv-orgを省略すると自行(100)です。
  5. python3 router.py --routes <표> route <전문파일>(プレースホルダーは表と電文ファイルです)を追加してください。共通ライブラリlhstd.parseでヘッダーを読み、TX_CODEとRCV_ORGで決定し、ステップ4のJSONにguid・tx_code・rcv_orgを加えて1行で出力します(終了コードはlookupと同じです)。形式が誤った電文なら、1行目にE102 <사유>(プレースホルダーは理由です)を出力し、終了コード2で終わります。
  6. route <전문파일> --reply <경로>(プレースホルダーは電文ファイルとパスです)を追加してください。決定がNONEなら、lhstd.replyで応答コードE101のレスポンス電文をそのパスに書き、終了コード3で終わります。ルーティングできた電文にはファイルを作りません。
  7. グローバルオプション--audit <경로>(プレースホルダーはパスです)を追加してください。指定されたら、routeの決定ごとに(NONEも含む)そのファイルにJSONを1行追記します。キーはts(決定時刻)・guid・tx_code・rcv_org・rule・targetです。指定されなければ何も書きません。
  8. 受信箱/opt/lab/fixtures/eaimw/route/inbox/全体をステップ5のrouteで処理して、/root/eaimw/route/dispatch.csvを作成してください。見出し行はfile,tx_code,rule,target、ファイル名順です。形式エラーは파일,,E102,(プレースホルダーはファイル名です)、NONEはtargetを空にします。

参考

インターフェース一覧をルーティング表に整理する

/opt/lab/fixtures/eaimw/route/interfaces.csvから、運用中の最新バージョンだけを選び、/root/eaimw/route/routes.csv(tx_code,target,mode,timeout_ms)を作成してください。

順序が重要です。まず状態が運用の行だけを残し、そのあと取引コード(空白除去・大文字)ごとにバージョンをintに変換して、最大の行を選びます。バージョン9と10が両方あるコードがあります。タイムアウトには1.5のような小数もあります。

完全一致ルーター

/root/eaimw/route/router.pyのlookupが、表から取引コードが完全に同じ行を探してJSONで答え、なければNONEと終了コード3で終わるようにしてください。

csv.DictReaderで表を読み、取引コード→行の辞書を作ります。末尾が*の行は、このステップでは飛ばします。表のパスは--routesで受け取ります。採点ツールが自分の表を渡してきます。宛先が見つからないのはエラーではなく結果なので、JSONを出力してから3で終わります。

プレフィックスルール、長いほうが勝つ

末尾が*の行をプレフィックスルールとして扱ってください。完全一致 > 長いプレフィックス > 短いプレフィックスの順で、表の行の順序とは無関係にします。

プレフィックスの一覧を長さの降順に並べておけば、最初に一致したものが最も長いものです。「最初に一致した行」をファイルの順序で選ぶと、誰かが表を並べ替えた瞬間に結果が変わります。startswithで比較してください。inだと、途中にあっても一致してしまいます。

機関ルールを先に見る

lookupに--rcv-orgを追加し、受信機関が100でなければ、取引コードに関係なくFEP(rule ORG)へ送るようにしてください。

ORGは1位なので、表を探す前に見ます。表にない取引コードでも、外部機関宛てならNONEではなくFEPです。--rcv-orgの既定値を自行の100にしておけば、前のステップの呼び出しがそのまま動きます。

電文ヘッダーでルーティングする

route <電文ファイル>がlhstd.parseでヘッダーを読んで決定JSON(guid・tx_code・rcv_orgを含む)を出力し、形式エラーはE102と終了コード2で拒否するようにしてください。

open(ファイル, 'rb')で読んでlhstd.parseに渡すと、TX_CODE・RCV_ORG・GUIDが得られます。見るべきは送信機関(SND_ORG)ではなく受信機関です。保険会社が自社に送ってきた電文を、外部システムへ送ってはいけません。lhstd.FrameErrorを捕捉してE102で終了してください。

ルーティングできないものをE101で返す

routeに--reply <パス>を追加し、NONEならE101のレスポンス電文をそのパスに書いて、終了コード3で終わるようにしてください。

lhstd.reply(ヘッダー, 'E101')が、取引コードとGUIDを維持し、機関を入れ替えたレスポンス電文(bytes)を作ってくれます。ファイルは'wb'で書きます。ルーティングできた電文には作りません。

ルーティングの決定を監査ログに残す

グローバルオプション--audit <パス>が指定されたら、routeの決定ごとに(NONEも含む)、ts・guid・tx_code・rcv_org・rule・targetを含むJSONを1行追記するようにしてください。

open(パス, 'a')は追記し、'w'は消して書き込みます。監査ログは消えてはいけません。宛先だけ残しても「なぜそこへ行ったのか」には答えられません。どのルールに一致したか(rule)が核心です。

受信箱30件を振り分ける

受信箱全体をrouteで処理して、/root/eaimw/route/dispatch.csv(file,tx_code,rule,target)を作成してください。

ファイルごとにrouteを実行し、終了コードで振り分けます。2は形式エラー、3はNONEです。結果を宛先別に数えると、一方に集中しているところが見えます。形式が誤った電文の取引コードを無理に書かないでください。