2016-09-09 5 views
0

基本的には、スケジュールテーブルからすべての行を取得し、その行を個別に処理します。行がすでにコマンド表にある場合は、スキップしてください。それ以外の場合は挿入します。チェーンはPromise.all内でどのように適切に約束していますか?

私はPromise.all(rows.map(function(row){

return is_schedule_cmd_already_pending(schedule_id).then(function(num){ 
    return insert_into_pending_cmd(num, schedule_id, device_name, cmd); 
}); 

内の2つのチェーンの約束を持っている私は、印刷順序が同期している

is_schedule_cmd_already_pendingではconsole.logでSQL文を印刷しinsert_into_pending_cmd

このように、各行に対して、同期スタイルで実行する必要があります。

- schedule_id, device_name, day_code, schedule_time, schedule_hr, schedule_min, cmd - 
- curr_date_code, curr_h, curr_min - 
.. match up day .. 
~~ match up hour ~~ 
## match up d-h-m, run ## 
is_schedule_cmd_already_pending 
insert_into_pending_cmd 


- schedule_id, device_name, day_code, schedule_time, schedule_hr, schedule_min, cmd - 
- curr_date_code, curr_h, curr_min - 
.. match up day .. 
~~ match up hour ~~ 
## match up d-h-m, run ## 
is_schedule_cmd_already_pending 
insert_into_pending_cmd 


- schedule_id, device_name, day_code, schedule_time, schedule_hr, schedule_min, cmd - 
- curr_date_code, curr_h, curr_min - 
.. match up day .. 
~~ match up hour ~~ 
## match up d-h-m, run ## 
is_schedule_cmd_already_pending 
insert_into_pending_cmd 
....... 
....... 

代わりに、それはあなたのPromise.all()パターンが実行されている

- schedule_id, device_name, day_code, schedule_time, schedule_hr, schedule_min, cmd - 
- curr_date_code, curr_h, curr_min - 
.. match up day .. 
~~ match up hour ~~ 
## match up d-h-m, run ## 
is_schedule_cmd_already_pending 



- schedule_id, device_name, day_code, schedule_time, schedule_hr, schedule_min, cmd - 
- curr_date_code, curr_h, curr_min - 
.. match up day .. 
~~ match up hour ~~ 
## match up d-h-m, run ## 
is_schedule_cmd_already_pending 



- schedule_id, device_name, day_code, schedule_time, schedule_hr, schedule_min, cmd - 
- curr_date_code, curr_h, curr_min - 
.. match up day .. 
~~ match up hour ~~ 
## match up d-h-m, run ## 
is_schedule_cmd_already_pending 

....... 
....... 
....... 

insert_into_pending_cmd 
insert_into_pending_cmd 
insert_into_pending_cmd 

(つまり、すべては私が欲しいものではありませんこれは、一番最後に起こるinsert_into_pending_cmd)のような完全なコード

var config = require("./config.js"); 
var Promise = require('bluebird'); 
var mysql = require('promise-mysql'); 
var ON_DEATH = require('death'); 


var g_pool = null; 

function connect_db() { 
    g_pool = mysql.createPool(config.db_config); 
} 


function close_db() { 
    g_pool.end(function (err) { 
    // all connections in the pool have ended 
    }); 
} 



// http://thecodeship.com/web-development/alternative-to-javascript-evil-setinterval/ 
function interval(func, wait, times){ 
    var interv = function(w, t) { 
    return function() { 
     if(typeof t === "undefined" || t-- > 0) { 
     setTimeout(interv, w); 
     try { 
      func.call(null); 
     } 
     catch(e) { 
      t = 0; 
      throw e.toString(); 
     } 
     } 
     }; 
    }(wait, times); 

    setTimeout(interv, wait); 
} 


function get_current_utc_time() { 
    var curr_date_obj = new Date(); 
    var time_utc = ""; 

    // somehow the date format is not accurate. 
    //var time_utc = dateFormat(now, "yyyy-mm-dd h:MM:ss", true); 

    var year = curr_date_obj.getUTCFullYear(); 
    var month = add_zero(curr_date_obj.getUTCMonth() + 1); // count from 0 
    var date = add_zero(curr_date_obj.getUTCDate()); // count from 1 
    var hr = add_zero(curr_date_obj.getUTCHours()); 
    var min = add_zero(curr_date_obj.getUTCMinutes()); 
    // we ignore the second 
    var sec = "00"; 

    time_utc = year + "-" + month + "-" + date + " " + hr + ":" + min + ":" + sec; 

    console.log("-current utc-"); 
    console.log(time_utc); 

    return time_utc; 
}; 


// http://www.w3schools.com/jsref/jsref_getutchours.asp 
function add_zero(i) { 
    if (i < 10) { 
    i = "0" + i; 
    } 
    return i; 
} 


function insert_into_pending_cmd(msg_obj) { 
    console.log(); 
    console.log("-insert_into_pending_cmd-"); 

    var schedule_id = msg_obj.schedule_id; 
    var device_name = msg_obj.device_name; 
    var cmd = msg_obj.cmd; 
    var is_pending = msg_obj.is_pending; 

    if(is_pending) { 
    return Promise.resolve(); 
    } 
    else { 
    var curr_time = get_current_utc_time(); 
    var sql = "insert into Command set CommandDate = " + "'" + curr_time + "'" + "," + "RemoteName = " + "'" + device_name + "'" + "," + "CommandJSON = " + "'" + cmd + "'" + "," + "CommandComplete = 0" + "," + "ScheduleId = " + "'" + schedule_id + "'"; 

    return g_pool.query(sql).then(function(){ 
     return Promise.resolve(); 
    }); 
    } 
} 


function is_schedule_cmd_already_pending(msg_obj) { 
    console.log(); 
    console.log("-is_schedule_cmd_already_pending-"); 

    var schedule_id = msg_obj.schedule_id; 
    var device_name = msg_obj.device_name; 
    var cmd = msg_obj.cmd; 
    var is_run = msg_obj.is_run; 

    var local_msg_obj = {}; 

    if(is_run) { 
    var sql = "select count(*) as num from Command where ScheduleId = " + "'" + schedule_id + "'" + " and CommandComplete = 0 and (UNIX_TIMESTAMP(UTC_TIMESTAMP()) - UNIX_TIMESTAMP(CommandDate)) < 600 and (UNIX_TIMESTAMP(UTC_TIMESTAMP()) - UNIX_TIMESTAMP(CommandDate)) > 0"; 
    return g_pool.query(sql).then(function(rows){ 
     var num = rows[0].num; 
     if(num == 0) { 
       local_msg_obj = { 
        schedule_id: schedule_id, 
        device_name: device_name, 
        cmd: cmd, 
        is_pending: false 
       }; 
     return Promise.resolve(local_msg_obj); 
     } 
     else { 
       local_msg_obj = { 
      schedule_id: schedule_id, 
      device_name: device_name, 
      cmd: cmd, 
      is_pending: true 
     }; 
     return Promise.resolve(local_msg_obj); 
     } 
    }); 
    } 
    else { 
     local_msg_obj = { 
     schedule_id: schedule_id, 
     device_name: device_name, 
     cmd: cmd, 
     is_pending: true 
    }; 
    return Promise.resolve(local_msg_obj); 
    } 
} 




function is_matchup_schedule_time(row) { 
    // get all field 
    var schedule_id = row.ScheduleId; 
    var device_name = row.ScheduleRemoteName; 
    var day_code = row.ScheduleDaycode; 
    var schedule_time = row.ScheduleTime; 
    var cmd = row.ScheduleCommandJSON; 

    // get hour and min 
    var schedule_time_arr = schedule_time.split(":"); 
    var schedule_hour = schedule_time_arr[0]; 
    var schedule_min = schedule_time_arr[1]; 

    // print 
    console.log(); 
    console.log(); 
    console.log("- schedule_id, device_name, day_code, schedule_time, schedule_hr, schedule_min, cmd -"); 
    console.log(schedule_id); 
    console.log(device_name); 
    console.log(day_code); 
    console.log(schedule_time); 
    console.log(schedule_hour); 
    console.log(schedule_min); 
    console.log(cmd); 

    // curr date obj 
    var curr_date_obj = new Date(); 
    var curr_date_code = add_zero(curr_date_obj.getUTCDay()); 

    // print current 
    console.log(); 
    console.log("- curr_date_code, curr_h, curr_min - "); 
    console.log(curr_date_code); 
    console.log(add_zero(curr_date_obj.getUTCHours())); 
    console.log(add_zero(curr_date_obj.getUTCMinutes())); 

    // var 
    var msg_obj = {}; 

    // Match up day 
    if(day_code == curr_date_code) { 
    console.log(); 
    console.log(".. match up day .."); 

    // Match up hour 
    var curr_hour = add_zero(curr_date_obj.getUTCHours()); 
    if(schedule_hour == curr_hour) { 
     console.log(); 
     console.log("~~ match up hour ~~"); 

     // Match up min 
     var curr_min = add_zero(curr_date_obj.getUTCMinutes()); 
     if(schedule_min == curr_min) { 
     console.log(); 
     console.log("## match up d-h-m, run ##"); 

       msg_obj = { 
        schedule_id: schedule_id, 
        device_name: device_name, 
        cmd: cmd, 
        is_run: true          
       }; 

       return Promise.resolve(msg_obj);    
     } 
    } 
    } 
    else { 

    } 

    // 
    msg_obj = { 
    schedule_id: schedule_id, 
    device_name: device_name, 
    cmd: cmd, 
    is_run: false 
    }; 

    return Promise.resolve(msg_obj); 
} 


// NOTE ------------- 
function process_schedule_rows(rows) { 
    return Promise.mapSeries(rows, function(row) { 
     return is_matchup_schedule_time(row) 
      .then(is_schedule_cmd_already_pending) 
      .then(insert_into_pending_cmd) 
      .catch(function(e){ 
       throw e; 
      }) 
    }); 
} 


function do_schedule() { 
    console.log(); 
    console.log("---- start do_schedule ----"); 

    g_pool.query("select * from Schedule order by ScheduleId asc") 
    .then(process_schedule_rows) 
    .catch(function(e){ 
     throw e; 
    }); 
} 


// main func 
function main() { 
    console.log("db host:"); 
    console.log(config.db_host); 

    connect_db(); 

    interval(function(){ 
     do_schedule(); 
    }, 5000, undefined); 

    // Clean up 
    ON_DEATH(function(signal, err) { 
    console.log(); 
    console.log("-- script interupted --"); 
    console.log("close db"); 

    // close db 
    close_db();  

    process.exit(); 
    }); 

} 


// run main func 
main(); 
+0

ハングアップ期待通りと実際の出力の違いは、 'insert_into_pending_cmd'が複数回呼び出されるという事実です。 –

+1

これは順番に必要な出力ですか、 'row [1]'の処理全体が、 'row [0]'が完了するまで待ってから開始する必要がありますか? –

+0

あなたの必要なシーケンスが何であるかは不明です。 'Promise.all()'という定義は、すべての飛行中に必要な順番がないとき(例えば、順番どおりに実行したり終了したりすることができる)の予定に使用されます。だから、あなたはこれらの行の中で特定のシーケンスを要求しているのはちょっと奇妙なようです。あなたは 'Promise.all()'が何かをすることを期待しているか、あなたがそれを使うときに何を期待するのか分からない。 – jfriend00

答えて

1

です並行してすべての行を処理します。この行は、処理に関連するさまざまな操作の完了が任意の順序で実行されます。それがあなたのコードが動作するように設計されている方法です。

一度に1つの行が実行され、前の行が完全に終了した後で次の行が処理されるようにそれらをシーケンスするには、別のデザインパターンを使用する必要があります。アレイを処理している約束をシリアライズするための古典的な方法は、このような.reduce()を使用している:

// process each row sequentially 
rows.reduce(function(p, row) { 
    return p.then(function() { 
     return is_schedule_cmd_already_pending(schedule_id).then(function(num) { 
      return insert_into_pending_cmd(num, schedule_id, device_name, cmd); 
     }); 
    }); 
}, Promise.resolve()).then(function(data) { 
    // everything done here 
}).catch(function(err) { 
    // error here 
}); 

これは各行が約束鎖と鎖のdoesnの次のリンクのステップとして処理される拡張約束チェーンを作成します以前のものが完了するまで実行しないでください。


上記のスキームは、標準的なES6の約束事で動作します。私は個人的に明示的に、このために設計されてPromise.mapSeries()を持っているブルーバード約束ライブラリを使用して好む:

const Promise = require('bluebird'); 

Promise.mapSeries(rows, function(row) { 
    return is_schedule_cmd_already_pending(schedule_id).then(function(num) { 
     return insert_into_pending_cmd(num, schedule_id, device_name, cmd); 
    }); 
}).then(function(data) { 
    // everything done here 
}).catch(function(err) { 
    // error here 
}); 

FYI、あなたの実際のコードでのエラー処理の問題がたくさんあります。約束事は、非同期のエラー処理命令をより容易にします。下位レベルの操作を約束したり、データベースへの約束インタフェースを使用したりして、プロミスベースのコードでのみ制御フローとロジックを記述すれば、適切なエラー処理を書くのがはるかに簡単になります。このようなコード行は、通常の非同期コールバックの中にある適切なエラー処理を行うものではありません:

コントロールフロー内のすべてに約束を使用すると、非同期エラーを伝播して処理するのが非常に簡単になります。ネストされたプレーンな非同期コールバックでこれを正しく実行するのは実際は非常に難しく、コードにいくつかの間違いがあります。すべての非同期操作を約束に変換すれば、それを正しく行うことは容易です。

関連する問題