弊社では、SHANON MARKETING PLATFORMを使ってお客さまにサービスを提供していますが、お客さまのシステムとのデータ連携などで、スクラッチでアドオン開発をする場合があります。
アドオン開発しているときに「こんなのあったらいいなぁ」と思ったものを勉強も兼ねてscalaで試作してみました。
試作したのは、簡単なジョブスケジューラです。
ジョブスケジューラといえば、商用製品では、JP1、A-AUTOなど、OSSでは、Hinemosなどがあります。
小規模な開発をする場合、これら製品は、開発するアプリケーションとは別にインストールする必要がありますし、サーバのリソースも消費します。また商用製品は、ライセンス料を支払う必要があります。
また、EAIツールを使う方法もあります。EAIツールのSaaS製品も廉価なものが増えてきたので、EAIツールだけで対応可能であれば、EAIツールを使った方がいいです。
しかし、EAIツールでも対応できない開発をせざるを得ない場合があります。
お客さまのシステムとデータ連携するにあたって、開発中に感じたあったらいいなぁと思う機能を箇条書きにするとこんな感じです。
1. Playframework
多くの参考記事がWEBに掲載されているため、ここでは割愛します。
アドオン開発しているときに「こんなのあったらいいなぁ」と思ったものを勉強も兼ねてscalaで試作してみました。
試作したのは、簡単なジョブスケジューラです。
ジョブスケジューラといえば、商用製品では、JP1、A-AUTOなど、OSSでは、Hinemosなどがあります。
小規模な開発をする場合、これら製品は、開発するアプリケーションとは別にインストールする必要がありますし、サーバのリソースも消費します。また商用製品は、ライセンス料を支払う必要があります。
また、EAIツールを使う方法もあります。EAIツールのSaaS製品も廉価なものが増えてきたので、EAIツールだけで対応可能であれば、EAIツールを使った方がいいです。
しかし、EAIツールでも対応できない開発をせざるを得ない場合があります。
お客さまのシステムとデータ連携するにあたって、開発中に感じたあったらいいなぁと思う機能を箇条書きにするとこんな感じです。
- 画面からジョブ起動時刻を指定したい。
- バッチジョブが正常終了したかどうか画面で確認したい。
- ジョブ起動の条件を画面で指定したい。例えば、ジョブ3を起動するには、ジョブ1とジョブ2の両方が正常終了することが必要である。
- 異常終了したジョブに対して、補正後、画面からジョブを再実行したい。
- 画面からジョブ起動時刻を変更したい。
- playframeowrk 2.0.4
- akka 2.2 (playframeworkに同梱)
- quartz 2.1.5
- mybatis scala
1. Playframework
多くの参考記事がWEBに掲載されているため、ここでは割愛します。
2. Akka
Akkaとは、JVM上で動く、複数ノードで並行処理できるイベント駆動のフォールトトレランスを備えたフレームワークです。
今回は、Akkaの概要について記述します。
Akkaの特徴
Akkaは、下記特徴を持っています。
a. 並列化
Actorモデルを使えば、並列化のハンドリングをフレームワークで実施するため、プログラマは、ビジネスロジックのコーディングに集中することができます。
b. 拡張性
Actorモデルに実装されている非同期でメッセージを送信する機能を使って、アプリケーションをマルチコアのサーバでスケールアップすることが可能になります。
c. フォールトトレランス
Akkaは、Erlangの"Let It Crash"(クラッシュさせちゃいましょう)モデルを採用しています。できるだけActorをクラッシュさせないようにするのではなく、問題があったら一旦クラッシュさせて、何らかの対処(例えば、再実行とか、エラー後の処理を実行するとか)をするということです。
d. イベント駆動アーキテクチャー
Actorの非同期メッセージを送受信する機能は、イベント駆動です。例えば、Actor Aから、Actor Bにメッセージを非同期送信後、Actor Bの結果を取得して、それをActor C に非同期でメッセージ送信することができます。
e. トランザクションサポート
AkkaはSTM(Software Transactional Memory)を実装しています。これによって、複数のActorが共有するメモリ空間のトランザクション管理をすることができます。これによって、トランザクションのACIDのうち、「Atomicity/Consistency/Isolation」は担保されるようです。ただ、Durabilityが足りません。Durabilityを実現するには、STMインタフェースを拡張したモジュールを組み込むことが必要です。
f. ロケーション透過性
Akkaは、ローカル、リモートのサーバに配置されたプログラムを実行することができます。これによってマルチコア、分散環境でスケールしやすくなります。
g. Scala/JavaのAPI
Akkaは、アプリケーション作成時にScalaとJavaのAPIを提供しています。
今回は、Akkaでアプリケーションを作成するのに避けては通れないメッセージ送受信の実装を説明します。
Actorとは?
Actorとは、「状態」と「振る舞い」を持つメッセージ送受信するオブジェクトです。
他のActorから受信したメッセージは、Actor内のメールボックス(queue)に格納されます。
Actorは、下記のように定義します。
今回は、非同期メッセージ送信の基本的な2パターンについて、記述します。
ポイントは、
「伝達する(tell)だけなら"!"、問い合わせて(ask)結果を取得するなら"?"」
です。
1. tell
Actorにメッセージを渡して結果を取得しない場合は、下記のように"!"を使います。
これって、Java EEのMessageDrivenBeanでP to P でJSM(MQ)で電文を送信するのと同じことを実現していますよね。
ただ、Java EEのMessageDrivenBeanと比較するとコードがシンプルですね。
下記のように書いても同じ意味です。
2. ask
Actorにメッセージを渡して結果を取得する場合は、下記のように”?”を使います。
import文にakka.pattern.askを定義すると”?”がaskを意味します。
Akkaとは、JVM上で動く、複数ノードで並行処理できるイベント駆動のフォールトトレランスを備えたフレームワークです。
今回は、Akkaの概要について記述します。
Akkaの特徴
Akkaは、下記特徴を持っています。
a. 並列化
Actorモデルを使えば、並列化のハンドリングをフレームワークで実施するため、プログラマは、ビジネスロジックのコーディングに集中することができます。
b. 拡張性
Actorモデルに実装されている非同期でメッセージを送信する機能を使って、アプリケーションをマルチコアのサーバでスケールアップすることが可能になります。
c. フォールトトレランス
Akkaは、Erlangの"Let It Crash"(クラッシュさせちゃいましょう)モデルを採用しています。できるだけActorをクラッシュさせないようにするのではなく、問題があったら一旦クラッシュさせて、何らかの対処(例えば、再実行とか、エラー後の処理を実行するとか)をするということです。
d. イベント駆動アーキテクチャー
Actorの非同期メッセージを送受信する機能は、イベント駆動です。例えば、Actor Aから、Actor Bにメッセージを非同期送信後、Actor Bの結果を取得して、それをActor C に非同期でメッセージ送信することができます。
e. トランザクションサポート
AkkaはSTM(Software Transactional Memory)を実装しています。これによって、複数のActorが共有するメモリ空間のトランザクション管理をすることができます。これによって、トランザクションのACIDのうち、「Atomicity/Consistency/Isolation」は担保されるようです。ただ、Durabilityが足りません。Durabilityを実現するには、STMインタフェースを拡張したモジュールを組み込むことが必要です。
f. ロケーション透過性
Akkaは、ローカル、リモートのサーバに配置されたプログラムを実行することができます。これによってマルチコア、分散環境でスケールしやすくなります。
g. Scala/JavaのAPI
Akkaは、アプリケーション作成時にScalaとJavaのAPIを提供しています。
今回は、Akkaでアプリケーションを作成するのに避けては通れないメッセージ送受信の実装を説明します。
Actorとは?
Actorとは、「状態」と「振る舞い」を持つメッセージ送受信するオブジェクトです。
他のActorから受信したメッセージは、Actor内のメールボックス(queue)に格納されます。
Actorは、下記のように定義します。
import actors._ val actor = Akka.system.actorOf(Props(new ActorA))
今回は、非同期メッセージ送信の基本的な2パターンについて、記述します。
ポイントは、
「伝達する(tell)だけなら"!"、問い合わせて(ask)結果を取得するなら"?"」
です。
1. tell
Actorにメッセージを渡して結果を取得しない場合は、下記のように"!"を使います。
これって、Java EEのMessageDrivenBeanでP to P でJSM(MQ)で電文を送信するのと同じことを実現していますよね。
ただ、Java EEのMessageDrivenBeanと比較するとコードがシンプルですね。
actor ! msg
下記のように書いても同じ意味です。
actor tell msg
2. ask
Actorにメッセージを渡して結果を取得する場合は、下記のように”?”を使います。
import文にakka.pattern.askを定義すると”?”がaskを意味します。
import akka.dispatch.Await import akka.pattern.ask import akka.util.Timeout import akka.util.duration._ implicit val timeout = Timeout(5 seconds) val future = actor ? msg // enabled by the “ask” import val result = Await.result(future, timeout.duration).asInstanceOf[String]
"?"の代わりにaskと書いても同じ処理を意味します。
import akka.dispatch.Await import akka.util.Timeout import akka.util.duration._ implicit val timeout = Timeout(5 seconds) val future = actor ask msg // enabled by the “ask” import val result = Await.result(future, timeout.duration).asInstanceOf[String]
本来、エンタープライズアプリケーションでquartzを使いたくはないのですが、小規模なアプリケーションでは、cron形式でジョブを起動したいというニーズはまだまだあると思います。
googleで検索したら下記githubがあったので、これを使用しました。
このアプリケーションのすごいところは、cronっぽい形式で書かれたジョブスケジューラを起動するだけでなく、スケジュール済のジョブをキャンセルすることができます。
4. mybatis scala
今回のアプリケーションでデータストアとの連携にmyBatisを使った理由は、単に使ってみたかったからです。WEBアプリであれば、scalaのORMマッピングは、myBatisと比べてコードを書かずに済むものが沢山あるので、そちらを使うとよいと思います。
ただ、下記ケースは、myBatisがベストではないでしょうか。
- 大量のデータを登録する場合(1件1件insert文を登録していたら時間がかかる)
- テーブル間のリレーションが複雑になっているレガシーなシステムのRDBと連携する場合
コードのサンプルは下記githubが参考になりました。
https://github.com/mnesarco/mybatis-scala-samples-beta2
https://github.com/mnesarco/play2-mybatis-scala-better-sample
参考までに、今回作成したサンプルのgithubです。
scalaとplayframework2をインストールすれば簡単に動かせますので、よろしければどうぞ。
https://github.com/hirata-k/jobScheduler
下記コマンドを実行
git clone https://github.com/hirata-k/jobScheduler
cd jobScheduler
play run
しばらく待って、ブラウザで下記URLにアクセスする。
https://localhost:9000/
下記画面が出たら「Apply this script now!」をクリックする。
下記のように、定期的にジョブがログに出力される。
ジョブ画面
http://localhost:9000/jobcondition/
にブラウザからアクセスするとジョブ実行の前提条件を表示する。
この場合は、JobAを実行するためには、JobBが完了していることが必要という意味である。
しばらくコンソールを見ていると、下記のように各ジョブのログが出力される。
以上になります。
今後も、使っていただけそうなアプリケーションをどんどん開発して公開していきたいと考えています。
普段の業務にscalaとかAkkaとかを活用してみたい方、弊社ではエンジニアを採用しているようですので、是非弊社の門を叩いていただければと思います。
今回はこの辺で。
ではでは...