Activiti日本語情報ブログ

OSSのBPMエンジン Activitiの日本語情報をまとめています。

Alfresco Devcon 2018 参加レポート

概要

ActivitiプロジェクトのスポンサーであるAlfresco社の開発者向けイベント Alfresco Devcon 2018@Lisboa(1月16-18日)に参加して、Activitiの事例として自社製品のIM-BPMを紹介してきました。 また、Activitiの開発チームで集まって、Activiti 7の新機能やロードマップについてディスカッションしてきました。

Alfresco DevConは、Alfresco社のソフトウェア製品またはAlfresco社が運営しているOSSプロジェクトに関する開発者向けのイベントです。3日間を通して、60以上のセッションが実施されました。

https://pbs.twimg.com/media/DT1uZgrWAAAkOZY.jpg:large

https://pbs.twimg.com/media/DT3mvbQWAAEFLs-.jpg

レポート

16日(1日目)

イベント0日目。この日は、Alfresco社の製品の研修を受講してきました。ECM製品のAlfresco Content Service(ACS)と、Activitiを基盤にしたBPM Suite製品のAlfresco Process Services(APS)をそれぞれハンズオン形式でレクチャーしてもらいました。また、日本からACSスペシャリストの方が参加されていて、その方からAlfresco社のビジネスや製品について教わりました。

この日は、Activitiのチームメンバーもまだ到着しておらず、結構寂しく過ごしました(笑)。

17日(2日目)

イベント1日目。この日から、Activitiのチームメンバーと合流しました。

午前中は、各メンバーごとにActivitiに関するセッションを行いました。午後からは、APSのセッションに参加したり、APS・Activitiの利用者との座談会をやったりしました。夜は、Activitiの開発チームとAPSのコアメンバーでActiviti 7の機能(GraphQL)に関してディスカッションしました。ディスカッションのあとは、そのままみんなで夕食に出かけて、親睦を深めました。

Activitiのチームメンバーと始めて対面したので、中々感慨深かかったです。昨年の6月くらいから一緒に活動していますが、これまではずっとチャットやテレビ電話でのコミュニケーションだけだったので。

私のセッションでは、Activitiの採用事例としてIM-BPMの紹介を行いました。intra-martの開発基盤にActivitiをどのようにして組み込んだか、intra-martの顧客のニーズに合わせてActivitiをどのように拡張したかという点について主に説明しました。個人的にはあまりよろしくない出来でしたが(片言で英語の文章を読み上げただけみたいな感じです)、Q&Aだけでなくセッションの終了後も色々質問してもらったり、話かけてもらえたりしたので、興味は持ってもらえたのかなと思います。特にIM-BPMでActivitiを拡張した部分の説明に関して、興味を持ってもらえたようでした。

  • Activiti 開発チームのリーダー Mauricio@AlfrescoによるActiviti 7の概要説明

https://pbs.twimg.com/media/DTvEQdYX0AAweYQ.jpg:large

www.slideshare.net

  • Activiti 開発メンバーの Ryan@AlfrescoによるActiviti 7の詳細説明 & デモ

https://pbs.twimg.com/media/DTvbG60X0AAXChr.jpg

www.slideshare.net

  • intra-martにおけるActivitiの組み込み&拡張の事例紹介

https://pbs.twimg.com/media/DTxly2mWsAAaiuX.jpg:large

  • Activiti コミュニティ開発メンバー(カナダ) Igor DianovによるActiviti 7のGraphQL対応の説明

https://pbs.twimg.com/media/DT1PtMLWkAUstUL.jpg:large

18日(3日目)

イベント2日目。午前中だけイベントに参加して、午後から帰国しました。昨夜に引き続き、Activitiの開発チームでディスカッションしました。Activiti 7のロードマップや、Case Management対応などに関してみんなで検討しました。

f:id:lalalafrance:20180121121656j:plain

また、ランチイベントの際に、これまでのActivitiプロジェクトでのコントリビューションを認めてもらって、表彰してもらいました。

https://pbs.twimg.com/media/DT1UdE2WkAE4oYu.jpg:large

f:id:lalalafrance:20180121121344j:plain

その他

Activiti Advent Calendar 2017

  • このブログでも告知した割に、全然記事アップできてませんでした。もう2018年になってしまいましたが、Devconも終わって少し時間ができたので、ちょっとずつ埋めていこうかと思います。
  • 特に、Activiti 7回りについて書いていこうかと思います。

qiita.com

【告知】アドベントカレンダーはじめました(Activiti Advent Calendar 2017)

Activiti についてのアドベントカレンダーをはじめました。 qiita.com

現在開発を進めているActiviti 7の情報を日本語で発信するというところを主にやっていきたいと思っていますが、Activiti自体がニッチなこともあり、前半は入門的な内容と既存のバージョン(Activiti 5,6)の話を中心に進めていきたいと思います。

GitHubのスター数で見るBPMエンジン

はてなブログでフォローしてる方の記事を真似して、BPMエンジン版で書いてみました。 takezoe.hatenablog.com

まず、トップ5の選出ですが、シンプルにbpmで検索してスター数でソートしました。ただし、5つ目については、私の独断と偏見でbonitasoftを持ってきてます。本来であれば、Python製のfaxad/ActivFlowがきそうですね。

続いて、元記事と同じように、star-historyを使ってトップ5のスター数の推移を出してみました。camundaとbpmn-ioは合算してイメージしてください。 f:id:lalalafrance:20171119222528p:plain

注意書き

各プロダクトに関するコメントは、公正中立なものではありません。というのも、私自身がActivitiの関係者なのでポジショントークになってしまうのと、正直私がちゃんと触ったことがあるのはActivitiだけだからです。

Activiti/Activiti ★ 2803

github.com

ダントツの人気トップは、本ブログでも扱っているActivitiです。BPMN 2.0の仕様にそったプロセスを描けるEclipseベースのActiviti Designerと、BPMN 2.0の実行エンジンであるActiviti Engineがコアプロダクトです。既存のJavaアプリケーションに組み込んで使うだけでなく、外立てしたActiviti EngineとREST APIベースで連携できるActiviti RESTも提供されています。こちらは、Spring MVCをベースにしています。

今年は、ついにActiviti 6という初期バージョン(Activiti 5)の後継の正式版がリリースされました。アドホックなサブプロセスやDMN(Decision Model and Notation)エンジンの機能が追加されています。Designerに関しては、Eclipseを脱却し、WebベースのActiviti 6 App UIがリリースされました。

今後に関して言うと、さらに後継のバージョン Activiti 7の開発が進んでおり、こちらではMicroservicesへの対応とCMMN(Case Management Model and Notation)のサポートを目指しています。

camunda/camunda-bpm-platform ★ 484

bpmn-io/bpmn-js ★ 1017

github.com github.com

camundaは元々CamundaというBPM専門のソフトウェアコンサルタント会社がActivitiをフォークして始めたプロジェクトです。テーブル名なんかは未だにActivitiのプレフィックス(act_)が残っていますが、独自に進化も遂げていて、CMMNをサポートしたエンジンも提供しています。

また、プロセスのモデリングツールに関しては、Activitiよりクオリティの高いものを出しており、bpmn-ioという別プロジェクトとして立ち上げています。bpmn-ioは、この分野では中々のシェアを占めていると思います。むしろ、スター数を見ると、bpmn-ioはcamundaを上回っています。

https://camunda.org/assets/img/camunda-modeler/overview-bpmn-properties-panel.png

kiegroup/jbpm ★ 712

github.com

jbpmは、RedhatJBoss BPMのことです。こちらは長い歴史があるBPMエンジンで、最初に紹介したActivitiは、こちらの後継・刷新を目指すものとして始まったプロジェクトです。

flowable/flowable-engine ★ 446

flowableは、元々Activitiのリード開発者だったJoram BarrezとTijs RademakersがActivitiをフォークして昨年始めたプロジェクトです。フォークする際にメインコミッターをほとんど連れて行ったので、そう意味では正当なActivitiの後継かもしれません。

現時点で、Activitiとの大きな違いとしては、こちらは早くもCMMNをサポートしている点です。この10月にCMMN 1.1というCase Managementの標準仕様をサポートしたバージョンをリリースしています。

github.com

bonitasoft/bonita-engine ★ 53

github.com

[参考] Bossie Awards: The best open source applications

Githubのスター数と別の指標として米IDGの出版部門InfoWorldの編集者がその年の優れたオープンソースソフトウェアを選ぶ「Bossie Awards」というものがあります。こちらの指標だと、2013年時点ではActivitiとbonitasoftが選出されていますが、昨年の時点ではActivitiをforkしたcamundaが選出されていますね。

  • Bossie Awards 2016: The best open source applications
  • Bossie Awards 2015: The best open source applications
  • Bossie Awards 2014: The best open source applications
  • Bossie Awards 2013: The best open source applications

【Activiti Tips】プロセス図を出力する

概要

今回の記事では、Activiti Designerで作成したbpmnファイルを元にサーバサイドでプロセス図の画像ファイルを出力する方法をご紹介します。

プロセス図(プロセス定義)

RepositoryService.getProcessDiagram(String processDefinitionId)を利用することで、プロセス定義の静的なプロセス図を出力することが可能です。 プロセス図はInputStreamで返ってくるので、適宜ファイルへ出力してください。 https://www.activiti.org/javadocs/org/activiti/engine/RepositoryService.html#getProcessDiagram-java.lang.String-

f:id:lalalafrance:20170601223430p:plain

プロセス図(プロセスインスタンス

稼働中のプロセスのプロセス図を出力するには、インターフェース ProcessDiagramGeneratorを利用します。 実装は、ProcessEngineConfiguration().getProcessDiagramGenerator()で取得できます。

プロセス定義と違って、プロセスインスタンスの場合はアクティビティを指定してプロセス図を出力します。 プロセス図はInputStreamで返ってくるので、適宜ファイルへ出力してください。

// プロセス定義のBPMNモデルを取得
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDef.getId());

// プロセス図を出力
ProcessDiagramGenerator diagramGenerator = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
InputStream processInstanceDiagramStream = diagramGenerator.generateDiagram(bpmnModel, "png", runtimeService.getActiveActivityIds(processInstance.getId()));

f:id:lalalafrance:20170601223456p:plain

サンプルプログラム

プロセス定義, プロセスインスタンスそれぞれのプロセス図を出力するサンプルプログラムを以下のリポジトリで公開しています。

https://github.com/daisuke-yoshimoto/generateDiagram

上記のリポジトリのサンプルコードはシンプルさを重視しています。 実際の開発・運用において必ずしも適切な実装ではありません。参考にされる場合は、十分ご注意ください。 f:id:lalalafrance:20170601223430p:plain

【Activiti EL式】プロセスインスタンスの開始年を取得する

  • EL式と言っても、もはやコーディングしているような感じですが。。。

プロセスインスタンスの開始年を取得する

  • 以下のように暗黙オブジェクト executionからプロセスエンジンを取得してクエリでプロセスインスタンスを持ってくれば、プロセスの開始日時を解決できる。
  • getStartTime()の戻り値がjava.util.Dateなので、getYear()を実行すると、プロセスインスタンスの開始年を取得できる。
${execution.getEngineServices().getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(execution.getProcessInstanceId()).singleResult().getStartTime().getYear()+1900}

利用例

  • タイマーの中間イベントなどでプロセス開始年の特定の日付まで待たせる際などに利用できる。
  • 以下をタイマー中間イベントのTime date(ISO 8601)に設定すると、プロセス開始年の10月1日なったら自動で次に進むように利用できる。
${execution.getEngineServices().getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(execution.getProcessInstanceId()).singleResult().getStartTime().getYear()+1900}-10-01

f:id:lalalafrance:20170531210413p:plain

【Activiti Tips】実行中のプロセスインスタンスが参照するプロセス定義を差し替える

概要

今回の記事では、誤って不具合を含んだプロセス定義をリリースして運用を始めてしまった場合に、稼働中のプロセスインスタンスの参照するプロセス定義を変更する2つの方法を紹介します。

1つ目の方法は、不具合を修正したプロセス定義を作成し、再度デプロイを実施することです。 もう一つの方法は、すでにサーバ上にデプロイされた不具合を含んだプロセス定義を直接編集する方法です。

修正したプロセス定義の再デプロイ

Activitiの内部コマンド SetProcessDefinitionVersionCmdを利用して、プロセスインスタンスが参照しているプロセス定義のバージョンを変更することが可能です。 不具合を修正したプロセス定義をデプロイし、SetProcessDefinitionVersionCmdを利用して既存のプロセスインスタンスが再デプロイしたプロセス定義を参照するようにします。

ステップ

  1. 修正したプロセス定義をデプロイします

    不具合を修正したプロセス定義をデプロイし、デプロイ後のバージョンを確認します。

  2. SetProcessDefinitionVersionCmdの実行

    SetProcessDefinitionVersionCmdを利用して既存のプロセスインスタンスが参照するプロセス定義を、ステップ1でデプロイされたバージョンに差し替えます。SetProcessDefinitionVersionCmdには対象となるプロセスインスタンスのIDと差し替え対象のプロセス定義のバージョンを指定します。

   ((ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration()).getCommandExecutor().
        execute(
            new SetProcessDefinitionVersionCmd(processInstanceId, processDefinitionVersion)
        );

プロセス定義の直接変更

ActivitiのAPI DynamicBpmnServiceを利用し、既存のプロセスインスタンスが参照するプロセス定義を直接書き換えます。

ステップ

  • DynamicBpmnServiceのchange〜メソッドを利用して、変更内容を表すObjectNodeを作成します。
// シーケンスの分岐条件の内容を変更しています。
ObjectNode changedNode = processEngine.getDynamicBpmnService().changeSequenceFlowCondition("flow4", "${input == 'aaa'}");
  • DynamicBpmnServiceのsaveProcessDefinitionInfoメソッドを利用して、変更内容をプロセス定義へ反映します。
processEngine.getDynamicBpmnService().saveProcessDefinitionInfo(processInstance.getProcessDefinitionId(), changedNode);

サンプルプログラム

SetProcessDefinitionVersionCmd, DynamicBpmnServiceそれぞれを利用したサンプルプログラムを以下のリポジトリで公開しています。

https://github.com/daisuke-yoshimoto/process_def_migration_sample

上記のリポジトリのサンプルコードはシンプルさを重視しています。 実際の開発・運用において必ずしも適切な実装ではありません。参考にされる場合は、十分ご注意ください。

【Activiti開発入門】ビジネスロジックにおけるエラーハンドリング(1) - エラーのスローとキャッチ

概要

今回の入門記事では、Service Taskのビジネスロジックで発生したエラー(例外)のハンドリング方法についてご紹介します。

エラーハンドリングは、大きく2パターンに分かれています。1つ目は、発生したエラーをビジネスエラー(業務上のエラー)として扱い、業務プロセス上でその対応を行う方法です。2つ目は、単に一時的なシステムエラーとして扱い、リトライして対応する方法です。

前者は注文された商品の在庫切れなど業務ルールと合致しないケースが発生し、それに対応するをフローを記述する場合に利用します。後者は、データベースとの接続エラーなど技術的な原因に起因したエラーが発生した際に利用されます。

[コラム]システムエラーとビジネスエラー

Activitiでは、システムエラーとビジネスエラーを明確に区別し、ビジネスエラーを業務プロセス上で表現する方針にしています。これに関して、Activitiのフォーラムでは、以下のような見解が述べられています。

We've discussed this internally when we implemented the error boundary event, and we came to the conclusion that the error event is meant for errors with a 'process' meaning. A Java exception is something that always will be implemented by a developer, so that stuff needs to be hidden from the common model between devs and analysts. However if you want the semantics you write, you could catch your exception and call the ErrorEndEventActivityBehavior yourself.

我々はエラー境界イベントを実装する際に内部で議論し、エラーイベントはプロセスに関連するエラーを表すものであるという結論に至った。Javaの例外は開発者によって実装されるものなので、開発者とアナリストの間で共通となるモデルからは隠蔽されなければならない。

一方、BPMN2.0の仕様自体はもっとも簡素なもので、そもそもシステムエラーとビジネスエラーを区別していません。他のBPM製品(Oracle BPM)ではシステムエラーに関しても業務フロー上で明示的に表現させる方針の製品も存在します。

ビジネスエラー(業務エラー)のハンドリング

ビジネスロジックで発生したエラーを業務プロセス上で扱うには、JavaDelegateクラスからBpmnErrorをスローします。BpmnErrorをスローすることでエラーイベントが発生し、業務プロセス上のエラー境界イベントもしくはイベントサブプロセスでエラーイベントに対する制御フローを記述することが可能です。

  1. エラーイベントの発生(BpmnErrorのスロー)

  2. エラーイベントに対する制御フローの作成

(参考)Activiti User Guide https://www.activiti.org/userguide/#serviceTaskExceptionHandling

エラーイベントの発生(BpmnErrorのスロー)

エラーイベントを発生させるために、ビジネスロジック(JavaDelegateクラス)の内部からorg.activiti.engine.delegate.BpmnErrorクラスをスローします。

https://www.activiti.org/javadocs//org/activiti/engine/delegate/BpmnError.html

エラーのパターンが複数あり、それぞれを業務プロセス上で区別したい場合は、BpmnErrorクラスのコンストラクタにてエラーコードを指定します。指定したエラーコードは、エラーイベントのエラーコードとなります。

import org.activiti.engine.delegate.BpmnError;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

public class SampleJavaDelegate implements JavaDelegate {

    @Override
    public void execute(DelegateExecution execution) throws Exception {
        String inputVar = (String) execution.getVariable("input_var");
        if("error1".equals(inputVar)){
            // エラーのパターンに応じたエラーコードを指定します。
            throw new BpmnError("Error_Code1");
        }else if("error2".equals(inputVar)) {
            // エラーのパターンに応じたエラーコードを指定します。
            throw new BpmnError("Error_Code2");
        }
        
    }

}

エラーイベントに対する制御フローの作成

発生したエラーイベントをキャッチし、制御するフローを業務プロセス上に記述します。ビジネスロジックを実行するサービスタスクに対して、エラー境界イベントもしくはエラー開始イベントから始まるイベントサブプロセスを配置し、サービスタスクから発生したエラーイベントに対する制御を記述します。

エラー境界イベント f:id:lalalafrance:20161226003817p:plain

エラー開始イベントから始まるイベントサブプロセス

f:id:lalalafrance:20161226003754p:plain

エラーイベントのパターンが複数存在する場合は、キャッチするエラー境界イベント・エラー開始イベントを各パターンごとに複数配置し、エラーイベントのエラーコードとのひもづけをキャッチするエラー境界イベント・エラー開始イベントのMain configのError code属性に指定します。

サンプルフロー

ユーザの入力ごとに2つのエラーハンドリングのパターンを実装したプロセスのサンプルを以下のページで公開しています。 https://github.com/daisuke-yoshimoto/sample_java_error_handling

上記のリポジトリのサンプルコードはシンプルさを重視しています。 実際の開発・運用において必ずしも適切な実装ではありません。参考にされる場合は、十分ご注意ください。

システムエラーのハンドリング

ビジネスロジック(JavaDelegateクラス)からExceptionクラスのサブクラスをスローした場合は、システムエラーが発生したとしてActivitiに判断され、リトライされます。リトライのパターンは、サービスタスクが同期(Asynchronous属性が無効)か非同期(Asynchronous属性が有効)かの設定によって異なります。

サービスタスクが同期(Asynchronous属性が無効)で実行される場合

ビジネスロジック(JavaDelegateクラス)から例外がスローされ、システムエラーが検知されると、一つ前のタスクまで戻ります(トランザクション全体がロールバックされる)。

サービスタスクが非同期(Asynchronous属性が有効)で実行される場合

非同期の設定の場合、サービスタスクはジョブとして非同期スレッドで実行されます。この状態では、一つ前のタスクまでのトランザクションはすでに確定しているため、サービスタスクのジョブ内でシステムエラーが発生した場合でも一つ前のタスクまで戻ることはありません。

ジョブが非同期スレッドにて、3度リトライされます。3度のリトライでもエラーが発生した場合は、ジョブテーブルに格納され、Activiti Explorerのジョブ一覧から手動で再実行できます。Activiti Explorer以外の場合は、APIから再実行する必要があります。

(参考)Activiti User Guide

http://www.activiti.org/userguide/#asyncContinuations http://www.activiti.org/userguide/#failRetry