2017年8月7日月曜日

xrea の crontab

Python で作った Web サービスを xrea にデプロイしているのだが、crontab で嵌った。

1.実行結果のメールが来たり来なかったり
  crontab で処理が実行された後には 「結果・エラーメール(stdout と stderr に吐き出された内容)」が届くはずなのだが、届いたり届かなかったり

2.実行されるのは一時間に一回
 「ジョブの間隔は最短で1時間に1回とさせて頂いております」と明記されているのだが、crontab の設定で一時間に2回以上回る場合は、と解釈していたのだが違うようだ。
 crontab には 30件(スロット)設定できるのだが、手作業で起動時刻を設定しなおしても、一つのスロットにつき一時間に二回以上は実行しない様子。実行されるスクリプトを手直しして、再実行させようとして同じスロットで起動時刻を変更しても、最初に実行した時刻から一時間経過しないと実行されない。
 一時間ほど嵌って、あきらめて寝て、布団の中で気が付いた。

2017年1月3日火曜日

Xmarin+Android framework で RunOnUiThread() を使うとデータが化けた話

 Xmarin+Android framework でシステム開発中。

 ストリーミングのデータを処理し、エラーを見つけたらリアルタイムに画面に表示する機能を実装していた。

 表示にはエラーが発生した時刻(ms まで)と期待したデータと実際に受信したデータを表示するようにしたのだが、期待したデータの表示が、こちらが期待した値にならない。データ処理ロジックが間違っているのかと数時間ソースを追ったのだが原因がつかめない。

(ちなみに、どういうわけかブレークポイントが使えない。設定するとプログラムが止まるタイミングでアプリが終了する)

 いろいろやっていくうちに、「画面表示だと、別スレッドだから時間表示がずれる。ログに吐かせてみよう」ということで、同じ内容をログにはかせると期待したデータが表示された!

----
 原因だが、RunOnUiThread() に渡したコードに、クラス内で定義した変数を持たせたために、表示スレッドが実行される前にその変数が更新されてしまうことが原因だった。

class foo
  {
  int LastData;

  void bar (int data)
  {
    ....
    parentActivity.RunOnUiThread(() =>
    {
      parentActivity.UpdateTestInfo("Error Info: " + DateTime.Now.ToString("HH:mm:ss.fff") + ":" + LastData.ToString("x2") + "-" + data.ToString("x2") + "\n");
    }
  }

 というようなコードを書いたのだが、コードが UiThread のキューに積まれるときに、

  • date は関数終了と同時に消滅するローカル変数だから値渡し
  • LastData は、関数が終了しても消滅しないので参照渡し
となったらしい。

 ストリーミングデータを処理しているため LastData は常に更新されていく。そのため画面に表示されるのは、RunOnUiThread() が実行された時点での LastData の値ではなく parentActivity.UpdateTestInfo(...)が実行されるときの LastData の値、
 date の方は値渡しなのでRunOnUiThread() が実行された時の値に。

 変数は参照わたしなんかしないで、キューに積む時点の値で全部値渡しにしてしまえばいいのに。