[EC-CUBE]売上集計をリアルタイムで行うとタイムアウトする

売上集計をリアルタイムでなく、バッチモードで行うとタイムアウトしないという
ただのタイムアウト回避方法。
デフォルトはリアルタイム集計法。

リアルタイムで集計したいのもわかるけど。
データが大量だとタイムアウトが発生する。

商品別集計したときの画面イメージはこんな感じ。

ちなみに、リアルタイムは

1. 「月度で集計する」や「期間で集計する」ボタンが押されたときにその場で集計→集計データ格納→集計データ取得→表示、と行う方法。

バッチモードだと

2. あらかじめ売上データを集計しておき、「月度で集計する」や「期間で集計する」ボタンが押されたときには、すでに集計して格納済みのデータを取得→表示、と行う方法。

グラフ表示も同じロジックを通るため、これまたタイムアウトで表示できなかったり。
というわけで。

先にバッチモードで集計しておいたデータを表示するようにカスタマイズする。

パラメータの変更


まずは管理画面から

管理画面>システム設定>パラメータ設定>DAILY_BATCH_MODE

をfalseからtrueに変更して登録する。

売上集計バッチの作成

次に、売上集計を定期的におこなうバッチを新規作成する。

/data/script/execute_batch_daily.php
  1. #!/usr/bin/env php
  2. <?php
  3. /**
  4.  * デイリーバッチ起動スクリプト
  5.  * @author y-nakajima
  6.  */
  7. require_once( dirname(__FILE__) . "/../install.php");
  8. define( "CLASS_PATH", DATA_PATH . 'class/');
  9. define( "CLASS_EX_PATH", DATA_PATH . 'class_extends/');
  10. define( "CACHE_PATH" . DATA_PATH . 'cache/');
  11.  
  12. require_once(CLASS_EX_PATH . "util_extends/GC_Utils_Ex.php");
  13. require_once(CLASS_EX_PATH . "util_extends/SC_Utils_Ex.php");
  14. require_once(CLASS_EX_PATH . "db_extends/SC_DB_MasterData_Ex.php");
  15. require_once(CLASS_EX_PATH . "db_extends/SC_DB_DBFactory_Ex.php");
  16. require_once(CLASS_PATH . "SC_DBConn.php");
  17. require_once(CLASS_PATH . "SC_Query.php");
  18. require_once(CLASS_PATH . "SC_SelectSql.php");
  19.  
  20. // アプリケーション初期化処理
  21. $objInit = new SC_Initial_Ex();
  22. $objInit->init();
  23.  
  24. $usage = <<<USAGE
  25.  
  26. php -f execute_batch_daily.php start term
  27. 集計期間を指定して売上集計します。
  28.  
  29. start 集計開始日。何日前の売上から集計するか。1から365以内で指定。
  30. term 集計対象期間。何日分の売上を集計をするか。1から365以内で指定。
  31.  
  32. 例:昨日の売上を集計します。
  33. php -f execute_batch_daily.php 1 1
  34.  
  35.  
  36. USAGE;
  37.  
  38.  
  39. if( $argc != 3){
  40. echo($usage);
  41. exit(1);
  42. }
  43.  
  44. $start = $argv[1];
  45. $term = $argv[2];
  46. if(!is_numeric( $start ) || !is_numeric( $term )){
  47. echo($usage);
  48. exit(1);
  49. }
  50.  
  51. $start = intval( $start ):
  52. $term = intval( $term );
  53.  
  54. if( $start < 1 || $start > 365 || $term < 1 || $term > 365){
  55. echo($usage);
  56. exit(1);
  57. }
  58.  
  59. if($term > $start ){
  60. echo($usage);
  61. exit(1);
  62. }
  63.  
  64. $objBatch = new SC_Batch_Daily_Ex();
  65. $objBatch->lfStartDailyTotal( $term, $start, true);
  66.  
  67. ?>
  68.  
  69.  

バッチの修正


/data/class/batch/SC_Batch_Daily.php

のlfStartDailyTotal()を修正する。
修正したのは3点。
  • キャンセル、削除になった受注詳細情報を削除しているのをコメントアウト。
  • 最後のバッチ実行からLOAD_BATCH_PASS秒経過していないと実行しない。のログがうまく出力されないので修正。
  • 集計のforループ

  1. /**
  2.   * バッチ処理を実行する.
  3.   *
  4.   * @param mixed $argv コマンドライン引数
  5.   * @return void
  6.   */
  7. function execute($argv = "") {
  8. $term = 0;
  9. $start = 1; // 集計期間は、$start~$termの間となる。通常前日分から。
  10. $command = false;
  11.  
  12. // 集計対象期間の取得(指定日分さかのぼる)
  13. if (SC_Utils_Ex::sfIsInt($argv[1]) && $argv[1] <= 365) {
  14. $term = $argv[1];
  15. $command = true;
  16. }
  17.  
  18. // 集計開始日
  19. if (SC_Utils_Ex::sfIsInt($argv[2]) && $argv[2] <= 365) {
  20. $start = $argv[2];
  21. $command = true;
  22. }
  23.  
  24. if($term > 0) {
  25. // 集計の開始
  26. $this->lfStartDailyTotal($term, $start, $command);
  27. }
  28. }
  29.  
  30. // 集計の開始
  31. function lfStartDailyTotal($term, $start, $command = false) {
  32.  
  33. $now_time = time();
  34.  
  35. // グラフ画像の削除
  36. $path = GRAPH_DIR . "*.png";
  37. system ("rm -rf $path");
  38.  
  39. // 削除された受注データの受注詳細情報の削除
  40. $objQuery = new SC_Query();
  41. /*
  42. EC-CUBE全体をgrepしてみたが、なぜ受注詳細情報だけを削除してしまうのか不明なので削除しないでおく。
  43. 商品別集計もdel_flg=0でキャンセルステータスではない注文から集計してるので影響はなさそう。
  44.   $where = "order_id IN (SELECT order_id FROM dtb_order WHERE del_flg = 1)";
  45.   $objQuery->delete("dtb_order_detail", $where);
  46. */
  47. // 最後に更新された日付を取得
  48. $ret = $objQuery->max("dtb_bat_order_daily", "create_date");
  49. list($batch_last) = split("\.", $ret);
  50. $pass = $now_time - strtotime($batch_last);
  51.  
  52. // 最後のバッチ実行からLOAD_BATCH_PASS秒経過していないと実行しない。
  53. if($pass < LOAD_BATCH_PASS) {
  54. // GC_Utils_Ex::gfPrintLog("LAST BATCH " . $arrRet[0]['create_date'] . " > " . $batch_pass . " -> EXIT BATCH $batch_date");
  55. $batch_next = date( "Y-m-d H:i:s", strtotime($batch_last) + LOAD_BATCH_PASS );
  56. GC_Utils_Ex::gfPrintLog("LAST BATCH " . $batch_last . " NEXT BATCH AFTER $batch_next -> EXIT BATCH");
  57. return;
  58. }
  59.  
  60. // 集計
  61. // for ($i = $start; $i < $term; $i++) {
  62. for ($i = $start; $k = 0; $i--, $k++ ) {
  63. // 基本時間から$i日分さかのぼる
  64. $tmp_time = $now_time - ($i * 24 * 3600);
  65.  
  66. $batch_date = date("Y/m/d", $tmp_time);
  67. GC_Utils_Ex::gfPrintLog("LOADING BATCH $batch_date");
  68.  
  69. $this->lfBatOrderDaily($tmp_time);
  70. $this->lfBatOrderDailyHour($tmp_time);
  71. $this->lfBatOrderAge($tmp_time);
  72.  
  73. // タイムアウトを防ぐ
  74. SC_Utils_Ex::sfFlush();
  75. }
  76. }
  77.  

サーバへcronをセット。


サーバ(UNIX系OS)にcronをセットする。毎晩AM2:00に前日分の売上を集計するようにするには
以下のようにする。

$ crontab -e

0 2 * * * /usr/local/bin/php -f /path/to/eccube/data/script/execute_batch_daily.php 1 1 2>&1 > /dev/null


リアルタイム集計でもタイムアウトを防ぐようにする


SC_Batch_Daily::lfRealTimeDailyTotal()
のforループ中の最後に
SC_Utils_Ex::sfFlush();
を追加した。

  1. // リアルタイムで集計を実施する。集計が終了しているレコードは実施しない。
  2. /*
  3.   $sdate:YYYY-MM-DD hh:mm:ss形式の日付
  4.   $edate:YYYY-MM-DD hh:mm:ss形式の日付
  5.   */
  6. function lfRealTimeDailyTotal($sdate, $edate) {
  7. $pass = strtotime($edate) - strtotime($sdate);
  8. $loop = intval($pass / 86400);
  9.  
  10. for($i = 0; $i <= $loop; $i++) {
  11. $tmp_time = strtotime($sdate) + ($i * 86400);
  12. $batch_date = date("Y/m/d H:i:s", $tmp_time);
  13. $objQuery = new SC_Query();
  14. $arrRet = $objQuery->select("order_date, create_date", "dtb_bat_order_daily", "order_date = ?", array($batch_date));
  15. // すでにバッチ処理が終了しているかチェックする。
  16. $count = count($arrRet);
  17. if( $count > 0 ) {
  18. list($create_date) = split("\.", $arrRet[0]['create_date']);
  19. list($order_date) = split("\.", $arrRet[0]['order_date']);
  20. $create_time = strtotime($create_date);
  21. $order_time = strtotime($order_date);
  22. // オーダー開始日より一日以上後に集計されている場合は集計しなおさない
  23. if($order_time + 86400 < $create_time || $tmp_time > time()) {
  24. GC_Utils_Ex::gfPrintLog("EXIT BATCH $batch_date $tmp_time" . " " . time());
  25. continue;
  26. }
  27. }
  28. GC_Utils_Ex::gfPrintLog("LOADING BATCH $batch_date");
  29. $this->lfBatOrderDaily($tmp_time);
  30. $this->lfBatOrderDailyHour($tmp_time);
  31. $this->lfBatOrderAge($tmp_time);
  32.  
  33. // タイムアウトを防ぐ 2009.05.01 追加
  34. SC_Utils_Ex::sfFlush();
  35. }
  36. }
  37.  
最終更新:2009年05月01日 18:54
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。
添付ファイル