makotan _at_ gmail dot com

ServiceManager

ServiceManager

1 用途

主目的
・Thread処理の記述&テストの簡略化

Threadには
・Asyncメソッド
その場で処理を非同期に実行して即終了するタイプ
・待機処理系
ソケットの接続みたいに延々と実行を続けるタイプ
の二つ、ServiceManagerは待機処理を簡単に作る為のもの

Thread処理を記述するときに困ることは
・Threadが異常終了しても気がつき難い
・待機するとしても実は数パターンある

ということで
・Threadの実行状態を監視するモニタリング
・Threadの生死確認をして死んだ場合に特定のアクションをするStartupService
・Threadの記述をThreadや待機時間を意識せずに記述するOneService
から構成される

2 簡単な使い方

簡単な使い方を・・・

まず、AbstractGetRunServiceを継承したクラス(sample.PrintService)を作る
最小限記述が必要なのはvoid execute()とboolean canService()なので

public void execute(){
    System.out.println("実行!");
}
public boolean canService() {
    return true;
}

って書く

servicemanager.diconにPrintServiceを追記する

<component name="PrintService" class="sample.PrintService">
</component>

ServiceMonitorImplにこれを追加する

<component class="jp.starlogic.servicemanager.impl.ServiceMonitorImpl">
  <initMethod name="addService"><arg>"BuriAutoInvokeService"</arg></initMethod>
  <initMethod name="addService"><arg>"StartupService"</arg></initMethod>
  <initMethod name="addService"><arg>"PrintService"</arg></initMethod>
</component>

app.diconにservicemanager.diconをincludeすると
10秒に一回コンソール上に実行!という文字が表示されます。

これが最小限のServiceManagerの使い方。

UnitTestしたいときは普通にPrintServiceのexecuteを呼びだせばOK

3 ちょっと複雑なサービスの作り方

たとえばソケット通信みたいに通信する場合の記述方法はこんな感じ

public void initService() {
    connection(); //この中でsetSoTimeoutを設定
}

public void destroyService() {
    disconnect();
}

public boolean canService() {
    return true;
}

public void execute() {
    boolean isLoop = true;
    int readByte;
    while(isLoop) {
        try{
            readByte = inputStream.read();
            buffer.append((char) readByte);
            updateStatus();
            if((char) readByte == '\n') {
                receiveProcess();
                isLoop = false;
            }
        } catch (SocketTimeoutException e) {
            isLoop = false;
            continue;
        } catch (IOException e) {
            updateStatus(e);
            throw new IORuntimeException(e);
        }
    }
}

こんな感じ(未コンパイル&未テスト)
#ソケットのタイムアウト処理を使うことで無通信時障害を検出している

このクラスをServiceManager.diconに登録するときには

<property name="runningTime">5</property>
<property name="waitTime">0</property>
<property name="stopCheckInterval">5000</property>

この様に設定すると
executeは”最長”5ミリ秒間隔で呼びだされ
5秒間通信がなければ自動的にタイムアウトしたとしてソケットの切断他の必要な処理が実行されます。

4 ある特定の時刻に動作するサービスを作る

普通のPOJOとしてサービスを記述します。
servicemanager.diconファイルにこのように記述すれば毎時0分ごとに動作するようになります

<component name="Count" class="test.sampleservice.CountCronService">
</component>

<component name="CronTypeService" class="jp.starlogic.servicemanager.service.CronTypeService">
    <property name="executeStr">"Count.countUp()"</property>
    <property name="exeMinute">0</property>
    <property name="waitTime">1000</property>
    <property name="stopCheckInterval">50000</property>
</component>


exeMinuteの他にも
#数値を設定する
exeYear 年
exeMonth 月
exeDay 日
exeWeek 週(数値(WeekNo)を設定(addメソッドを使う)する)
exeHour 時
exeMinute 分
exeSecond 秒

#ここからはBoolean
lastDayOfMonth 月末
nearestWeekday 翌営業日
nearestHoliday 翌祝祭日
firstDayOfMonth 月初

が設定可能です
反する設定があった場合
たとえばexeDayが25なのにlastDayOfMonthがTrueとかの場合は
プログラムで適当に処理しますので注意してください

5 Tips

5-1 Threadが異常終了したときに任意の動作をさせたい

Threadが異常終了したときには
abortProcessed()
が呼びだされます。
そこでログを書く等の処理が可能です。

5-2 サービスを自動的に再起動させたい

diconファイルのコンポーネントのプロパティーに以下を追加してください

<property name="canReExecute">true</property>

5-3 トランザクションを自動で制御したい

デフォルトでスレッドのexecuteの直前にJ2ee.diconで設定するトランザクションを開始するように設定しています
もし、他のトランザクションを開始したい等の要件があれば
ExecuteServiceImplのaspectとして同じように追加してください。

5-4 サービスを再度動かしたい

一度停止したサービスを改めて動作させるときには
ServiceManagerのexecuteServiceでサービス名を渡せば再度動き始めます。

5-5 サービスの状態を知りたい

サービスが現在停止しているかどうかを判断する方法は
ServiceMonitorのboolean getIsTerminate(String serviceName);で確認します。
trueの場合はサービスが現在停止ししています、falseの場合は動作中です。

5-6 サービスを強制的に止めたい

ServiceMonitorのvoid setTerminate(String serviceName)を呼びだすとサービスを強制的に止めることが出来ます

5-7 アプリケーション終了と共にスレッドを全部停止したい

現在アプリケーション終了と共にすべてのスレッドが何もしなくても停止するはずです。
ただし、サービスの中で待機処理中(ソケットとか)等で終了が遅れる場合はあります。

5-8 実行開始〜次の実行開始までの時間を指定したい

<property name="runningTime">500</property>
<property name="waitTime">0</property>

このように設定すると
executeの中で200ms経った場合、300ms待った後にexecuteが呼びだされます
もし、executeの中で700ms経った場合、即座に再度executeが呼びだされます


普段はexecuteの後500ms待つ(waitTime)をするのがデフォです。

5-9 サービスのタイムアウトを設定したい

サービスのタイムアウトを設定する方法は
10000
を設定すると10000ms = 10秒でタイムアウトします
デフォルトでは60000msになってます

5-10 長時間のサービスでタイムアウトを回避したい

executeの中で連続してサービスする場合にタイムアウト判定を回避するには
executeの中の適当な箇所で
updateStatus()
を呼びだすとタイムアウト判定を延長することが可能です。