1. はじめての Process
最初の章では、引数に 1 を足して返すだけの Process を動かします。 書いたコードは短い関数ひとつですが、juiz はそれを読み込んで、ネットワーク越しに呼び出せる部品にしてくれます。
サンプルを用意する
Section titled “サンプルを用意する”サンプル集をクローンしてビルドします。以降のコマンドは、すべてクローンしたリポジトリのルートで実行します。
git clone https://github.com/OpenJUIZ/juiz_examples_rust.gitcd juiz_examples_rustcargo build各サンプルは共有ライブラリとして target/debug にビルドされます。
git clone https://github.com/OpenJUIZ/juiz_examples_python.gitcd juiz_examples_pythonpython3 -m venv .venvsource .venv/bin/activate # Windows では .venv\Scripts\activatepip install -r requirements.txt # juiz-cli が入るrequirements.txt には juiz-cli が書いてあり、juiz コマンドと pyjuiz が venv に入ります。Rust のツールチェーンは要りません。
Python はビルドの必要もありません。juiz コマンドが Python のファイルを直接読み込みます。
以降の手順は、この venv を有効にしたターミナルで実行してください。
git clone https://github.com/OpenJUIZ/juiz_examples_cpp.gitcd juiz_examples_cppcmake -S . -B buildcmake --build buildC++ 用のヘッダと libjuiz_sdk は CMake が juiz のリポジトリから取得してビルドします。初回は少し時間がかかります。
各サンプルは共有ライブラリとして build/plugins にビルドされます。
Process のコードを読む
Section titled “Process のコードを読む”引数 arg1 に 1 を足して返す Process です。
process/increment_process/src/lib.rs
use juiz_sdk::prelude::*;
#[juiz_process]fn increment_process(arg1: i64) -> JuizResult<Capsule> { log::trace!("increment_process({:?}) called", arg1); return Ok(jvalue!(arg1 + 1).into());}#[juiz_process] を付けた関数が Process になります。関数名 increment_process が Process の型名、引数名 arg1 がそのまま引数の名前になります。
戻り値は jvalue! で値を作り、Capsule に変換して返します。
このクレートは Cargo.toml で共有ライブラリ(crate-type = ["cdylib"])としてビルドする設定になっています。
process/increment_process_python.py
from juiz import juiz_process
@juiz_processdef increment_process_python(arg1: int = 0) -> int: """引数に 1 を足して返す""" print(f"increment_process_python: {arg1} -> {arg1 + 1}") return arg1 + 1@juiz_process を付けた関数が Process になります。関数名 increment_process_python が Process の型名です。
引数の名前・型・既定値は型ヒントと既定値から、出力の型は戻り値の型ヒント(-> int)から juiz が読み取ります。戻り値の型ヒントは省略できません。
ファイル名と関数名をそろえておくと、juiz はファイル名から関数を見つけられます。
process/increment_process_cpp/increment_process_cpp.cpp
#include "juiz/juiz.h"
// 引数 arg1 に 1 を足して返す Process//// manifest() で Process の名前と引数 (名前・説明・既定値) を宣言し、// PROCESS_FACTORY で juiz から呼び出せる関数として公開する。auto manifest() { return ProcessManifest{"increment_process_cpp"} .description("Adds 1 to arg1.") .add_int_arg("arg1", "value to be incremented", 1);}
std::optional<int64_t> increment_process_cpp(int64_t arg1) { return arg1 + 1;}
PROCESS_FACTORY(manifest, increment_process_cpp);C++ では、Process の型名と引数(名前・説明・既定値)を manifest() に自分で書きます。
関数の引数は manifest() で宣言した順に渡されます。値を返せないときは std::nullopt を返すとエラーになります。
最後に PROCESS_FACTORY で、juiz から読み込めるように公開します。
どの言語でも、Process は「引数を受け取って結果を返すだけ」の関数です。 外部の状態を読み書きしないので、同じ引数を渡せばいつも同じ結果が返ります(冪等)。 この性質のおかげで、Process はテストしやすく、あとでつないだり別のマシンに置いたりしても振る舞いが変わりません。
--process でファイルを指定して juiz を起動します。
juiz --process ./target/debug/libincrement_process.so -e -1 -dmacOS では拡張子が .dylib になります(./target/debug/libincrement_process.dylib)。
juiz --process ./process/increment_process_python.py -l python -e -1 -d-e で一度実行されるので、既定値の arg1 = 0 で呼ばれたことが表示されます。
increment_process_python: 0 -> 1juiz --process ./build/plugins/libincrement_process_cpp.so -l cpp -e -1 -dmacOS では拡張子が .dylib になります。
オプションの意味は次のとおりです。
| オプション | 意味 |
|---|---|
--process <パス> |
Process のファイルを読み込む |
-l <言語> |
ファイルの言語(rust / python / cpp、既定は rust) |
-1 |
読み込んだ Process から、インスタンスを 1 つ作る |
-e |
作ったインスタンスを、既定の引数で 1 回実行する |
-d |
HTTP ブローカーを 8000 番ポートで立ち上げて待機する(Ctrl+C で終了) |
ここで「読み込む」と「インスタンスを作る」が分かれていることに注目してください。
ファイルを読み込むと、juiz は Process の型(作り方)を覚えます。-1 を付けると、その型からインスタンスを 1 つ作ります。
インスタンス名は、型名の後ろに 0 を付けた名前(increment_process0 など)になります。
同じ型から、名前の違うインスタンスをいくつも作ることもできます(第 3 章で扱います)。
外から呼び出す
Section titled “外から呼び出す”juiz を起動したまま、別のターミナルを開いて Process を呼び出してみます。
まず、動いている Process の一覧を見ます。
juiz process list# => ["http://127.0.0.1:8000/process/increment_process0::increment_process"]juiz process list# => ["http://127.0.0.1:8000/process/increment_process_python0::increment_process_python"]juiz process list# => ["http://127.0.0.1:8000/process/increment_process_cpp0::increment_process_cpp"]表示された URL が、この Process の ID です。
http://127.0.0.1:8000 は Process がいる場所(ブローカー)、process/ の後ろは「インスタンス名::型名」を表しています。
この ID と引数を指定して、Process を呼び出します(call)。引数は JSON で渡します。
juiz process call "http://127.0.0.1:8000/process/increment_process0::increment_process" '{"arg1": 3}' -p# => CapsulePtr((value:Value(4), option: []))juiz process call "http://127.0.0.1:8000/process/increment_process_python0::increment_process_python" '{"arg1": 3}' -p# => CapsulePtr((value:Value(4), option: []))juiz を起動したターミナルには increment_process_python: 3 -> 4 と表示されます。
juiz process call "http://127.0.0.1:8000/process/increment_process_cpp0::increment_process_cpp" '{"arg1": 3}' -p# => CapsulePtr((value:Value(4), option: []))3 を渡して 4 が返ってきました。-p は結果を表示するオプションです。
何度呼び出しても、同じ引数なら同じ結果が返ることも確かめてみてください。
ブラウザから呼び出す
Section titled “ブラウザから呼び出す”-d で立ち上げた HTTP ブローカーは、Swagger UI も提供しています。ブラウザで次の URL を開きます。
http://127.0.0.1:8000/docs/一覧から PATCH /api/process/call を開き、「Try it out」を押して次のように入力し、「Execute」を押すと結果が返ってきます。
- identifier:
core://core/process/increment_process0::increment_process - Request body:
{"arg1": 3}
- identifier:
core://core/process/increment_process_python0::increment_process_python - Request body:
{"arg1": 3}
- identifier:
core://core/process/increment_process_cpp0::increment_process_cpp - Request body:
{"arg1": 3}
juiz コマンドも Swagger UI も、HTTP で同じ API を呼んでいるだけです。
つまり、HTTP を話せるプログラムなら、どの言語からでも Process を呼び出して結果を受け取れます。
これが、juiz をサーバー・クライアントのように使う call という使い方です。
やってみよう
Section titled “やってみよう”Process の中身を変えて、もう一度動かしてみましょう。
たとえば 1 を足す代わりに 2 倍にして返すように書き換え、ビルドし直して(Python はそのまま)juiz を起動し直すと、{"arg1": 3} に対して 6 が返ってくるはずです。
1 を引く Process(decrement_process)もサンプル集に入っています。同じ手順で動かせます。
- Process は、引数を受け取って結果を返すだけの冪等な関数です。Rust・Python・C++ のどれでも書けます。
- juiz はファイルを読み込んで Process の型を覚え、そこから名前の付いたインスタンスを作ります。
- 動いている Process には URL の形をした ID があり、ID と引数を指定して外から呼び出せます(call)。
次の章では、カウンタを題材にして、状態を持つ部品の書き方を学びます。状態を持つ: Container と ContainerProcess に進みましょう。