Blue Prism のプロセスを Python を使って実行する（SOAP）

はじめに
----------------
Blue Prism では、プロセス（ロボット）を WebService として公開し、外部から実行することができます。
この記事では、Python でクライアントを書いて、Blue Prism のプロセスを呼び出してみます。

WebService として公開したプロセスを実行するためには、2つの前提条件があります。[別記事](https://qiita.com/muuuuuwa/items/8fdd65eb0e0b71263644#blue-prism-%E3%81%AE%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B)を参照して前提条件を整えておきましょう。

> * A. Blue Prism のサーバーサービスが起動していること
> * B. public スイッチで起動したランタイムリソースがあること

プロセスを WebService として公開する
-------------------------------------------------

インタラクティブクライアントで、"システム" タブを開き、"プロセス > 公開" を選択します。画面右側に表示される "プロセスを公開" をクリックします。
<img width="506" alt="publish_process_00.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/20fce8b9-3c54-0844-3745-e8f329b724b1.jpeg">


WebService として公開したいプロセス（ここでは "logSample"）を選択し、"次へ" ボタンをクリックします。
<img width="395" alt="publish_process_01.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/335f0d39-43c0-31f1-6778-fdb0076412bd.jpeg">



"プロセスの公開名" を確認し、"完了" ボタンをクリックします。
<img width="395" alt="publish_process_02.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/f68031a4-83a1-c954-11b4-9f25c7c4e6d0.jpeg">


実際の運用を考えると、長いプロセスの本体と、処理の受付だけを行うプロセスを分割しておいて、WebService クライアントには同期的にレスポンスを返すような作りにしておく必要がありそうです。

Python でクライアントを作成する
-------------------------------------------------

### WSDL をダウンロードしておきます。

公開したプロセスの WSDL は、**ランタイムリソース** が公開しています（サーバーが WSDL を返すようなAPIは用意されていません。不思議ですね。。）。今回はランタイムリソースをポート8183で公開しているので、 ```http://127.0.0.1:8183/ws/``` をブラウザで開きます。すると、下記のように WebService として公開されたプロセスの一覧が表示されます。
<img width="403" alt="webservice_list.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/b36d790c-0722-9858-3e03-ae36080a7a9f.jpeg">


今回は、このページから WSDL ファイルをダウンロードして使用します。 Python スクリプトを開発するディレクトリに、```logSample.xml``` という名前で保存しておきます。

### 必要な Python モジュール をインストールする

[Pipenv](https://pipenv-ja.readthedocs.io/ja/translate-ja/) で Pythonスクリプトの開発環境を準備します。

```
% pipenv --python 3.7
Creating a virtualenv for this project…
Pipfile: /Users/m-nakamura/Documents/blueprism-process-invoker_/Pipfile
Using /Users/m-nakamura/.pyenv/versions/3.7.4/bin/python3 (3.7.4) to create virtualenv…
⠹ Creating virtual environment...Using base prefix '/Users/m-nakamura/.pyenv/versions/3.7.4'
New python executable in /Users/m-nakamura/.local/share/virtualenvs/blueprism-process-invoker_-30X4pztG/bin/python3
Also creating executable in /Users/m-nakamura/.local/share/virtualenvs/blueprism-process-invoker_-30X4pztG/bin/python
Installing setuptools, pip, wheel...
done.
Running virtualenv with interpreter /Users/m-nakamura/.pyenv/versions/3.7.4/bin/python3

✔ Successfully created virtual environment!
Virtualenv location: /Users/m-nakamura/.local/share/virtualenvs/blueprism-process-invoker_-30X4pztG
Creating a Pipfile for this project…
```

必要なライブラリをインストールします。Python で SOAPを使うには、[Zeep](https://python-zeep.readthedocs.io/en/master/) がおすすめのようなので、こちらを利用します。
Zeep、便利ですね！

```
% pipenv install zeep
Installing zeep…
Adding zeep to Pipfile's [packages]…
✔ Installation Succeeded
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
✔ Success!
Updated Pipfile.lock (663ec6)!
Installing dependencies from Pipfile.lock (663ec6)…
    ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 15/15 — 00:00:03
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
```

Zeep の機能に、[WSDLの内容を調べる機能](https://python-zeep.readthedocs.io/en/master/index.html#getting-started) があります。試してみると、プロセスの入力パラメーターと出力パラメーターが、 ```xsd:string``` 型になっていることがわかります。

```
% pipenv run python -m zeep logSample.xml 

Prefixes:
     xsd: http://www.w3.org/2001/XMLSchema
     ns0: urn:blueprism:webservice:logsample

Global elements:


Global types:
     xsd:anyType
     xsd:ENTITIES
     xsd:ENTITY
     xsd:ID
     xsd:IDREF
     xsd:IDREFS
     xsd:NCName
     xsd:NMTOKEN
     xsd:NMTOKENS
     xsd:NOTATION
     xsd:Name
     xsd:QName
     xsd:anySimpleType
     xsd:anyURI
     xsd:base64Binary
     xsd:boolean
     xsd:byte
     xsd:date
     xsd:dateTime
     xsd:decimal
     xsd:double
     xsd:duration
     xsd:float
     xsd:gDay
     xsd:gMonth
     xsd:gMonthDay
     xsd:gYear
     xsd:gYearMonth
     xsd:hexBinary
     xsd:int
     xsd:integer
     xsd:language
     xsd:long
     xsd:negativeInteger
     xsd:nonNegativeInteger
     xsd:nonPositiveInteger
     xsd:normalizedString
     xsd:positiveInteger
     xsd:short
     xsd:string
     xsd:time
     xsd:token
     xsd:unsignedByte
     xsd:unsignedInt
     xsd:unsignedLong
     xsd:unsignedShort

Bindings:
     Soap11Binding: {urn:blueprism:webservice:logsample}logSampleSoapBinding

Service: logSampleService
     Port: logSampleSoap (Soap11Binding: {urn:blueprism:webservice:logsample}logSampleSoapBinding)
         Operations:
            logSample(message: xsd:string) -> outmessage: xsd:string

```



logsample.xml という名前で WSDL ファイルを保存した同じディレクトリに、```logsample.py``` という名前で Python スクリプトを作成します。

~~~ python
from pathlib import Path
from zeep import Client

from requests import Session
from requests.auth import HTTPBasicAuth
from zeep.transports import Transport

# Blue Prism の認証情報を設定します
session = Session()
session.auth = HTTPBasicAuth('admin', 'admin_password_xxxxxx')

# 同じディレクトリに保存した WSDL ファイルのパスを取得します
wsdl = Path.cwd() / "logSample.xml"
client = Client(str(wsdl), transport=Transport(session=session))
service = client.service

# logSampleサービスの入力パラメーターを名前付き引数で指定します
res = service.logSample(message="hogehoge")

# 単一の文字列型出力パラメータは、レスポンスとして直接返されます
print(type(res))
print(res)
~~~


プロセスを実行する
-------------------------------------------------

先ほど作成した ```logSample.py``` が保存されているディレクトリで、スクリプトを実行します。プロセスの出力パラメーターが出力され、プロセスが実行されたことが確認できます。

~~~
% pipenv run python logSample.py
<class 'str'>
exec at 04/01/20 23:25:12hogehoge
~~~

インタラクティブクライアントからも実行されたことが確認できます。"コントロール" タブを開き、"セッション管理 > 今日" を開きます。
<img width="735" alt="process_results.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564576/8a1dff8c-b02b-0d4c-b821-c34a76202dfe.jpeg">



問題点
-------------------------------------------------

機能を試してみて、下記点が気になりました。

* ランタイムリソースが WebService のエンドポイントになっている。ランタイムリソースはエフェメラルなものという位置付けなので、エンドポイントの場所がコロコロ変わる可能性がある。利用する側からすると、安定して利用できないという問題が生じるのでは？
    * サーバー側に WebService のエンドポイントがあった方が良いのではないか？ なぜそのようなデザインになっているのか、理由があるのかもしれない。。。
    * 次善の策として、ランタイムリソースの一覧を引くためのAPIがあれば良いかな、とも思ったが、それも無さそう。
    * 「ヘルプ - Blue PrismリソースPCコマンド」に、"pool", "members", "availability", "proclist" のようなコマンドがあるが、ランタイムリソース全体を把握するための手段は無さそう。
    * Automate.exe の起動オプションに、バインドするIPアドレスを指定するものが無い。
* ライセンス不足などで、プロセスを起動するセッションの作成に失敗した場合、WebServiceクライアント側でリトライの作り込みが必要になってしまう。ワークキューにセッションを使用することなくエンキューできるAPIがほしい。。。