2017-05-19 5 views
0

Ich erstelle eine Versprechen-Funktion zur Verarbeitung einer langfristigen Abfrage-Aufgabe. Irgendwann wird die Aufgabe für Stunden blockiert. Ich möchte eine Auszeit einstellen, um die Aufgabe zu stoppen. Unten ist der Code.Knoten js stoppen lange Prozess-Aufgabe, wenn Promise es ablehnt

Es kann Fehlermeldung korrekt zurückgeben, aber es läuft immer noch connection.execute() für lange Zeit, bevor zu stoppen. Also wie kann man es sofort stoppen, wenn es eine abweisende Nachricht zurückgibt?

Danke!

function executeQuery(connection, query) { 
return new Promise((resolve, reject) => { 
    "use strict"; 
    //long time query 
    connection.execute(query, function (err, results) { 
     if (err) reject('Error when fetch data'); 
     else resolve(results); 
     clearTimeout(t); 
    }); 

    let t = setTimeout(function() { 
     reject('Time Out'); 
    }, 10); 
}) 


(async() => { 
"use strict"; 
oracle.outFormat = oracle.OBJECT; 

try { 
    let query = fs.readFileSync("query.sql").toString(); 
    let results = await executeQuery(connection, query); 

    console.log(results.rows); 
} catch (e) { 
    console.log(`error:${e}`); 

} 
+0

"* es läuft noch connection.execute() *" - Nun, Sie müssen eine Möglichkeit, um diesen Vorgang abzubrechen. Bietet die Bibliothek, die Sie verwenden, das? Wenn nein, haben Sie grundsätzlich kein Glück. Aber sagen Sie uns doch, welche Bibliothek es ist, damit wir Ihnen helfen können, eine Lösung zu finden. – Bergi

+0

Beenden Sie einfach Ihre Knoten Aufgabe mit 'process.exit' im Falle eines Fehlers, wenn Sie alles abbrechen wollen – Bergi

+0

@Bergi: Kill Ihren Prozess jedes Mal, wenn eine Abfrage fehlschlägt? Das klingt nach einer Verweigerung des Dienstes an dir selbst. – arboreal84

Antwort

1

So how can stop it immediately when it return reject message?

Nach der Dokumentation, Sie connection.break verwenden können:

return new Promise((resolve, reject) => { 
    connection.execute(query, (err, results) => { 
     if (err) reject(err); 
     else resolve(results); 
     clearTimeout(t); 
    }); 

    const t = setTimeout(() => { 
     connection.break(reject); // is supposed to call the execute callback with an error 
    }, 10); 
}) 

Stellen Sie sicher, auch release die Verbindung in einem finally Block.

+0

ja, es funktioniert, vielen Dank! –

+0

Danke für deine Hilfe, vergiss das. Diese Antwort wurde bereits akzeptiert! –

1

Versuchen Sie dies (mit bluebird Versprechen):

var execute = Promise.promisify(connection.execute); 

function executeQuery(connection, query) { 
    return execute.call(connection, query) 
    .timeout(10000) 
    .then(function (results) { 
     // handle results here 
    }) 
    .catch(Promise.TimeoutError, function (err) { 
     // handle timeout error here 
    }); 
    .catch(function (err) { 
     // handle other errors here 
    }); 
}; 

Wenn dies immer noch blockiert, gibt es eine Möglichkeit, dass der Datenbanktreiber Sie verwenden, anstatt asynchron tatsächlich synchron ist. In diesem Fall wäre dieser Treiber nicht kompatibel mit der Ereignisschleife des Knotens und Sie möchten vielleicht in einen anderen schauen.

+0

Das ist im Grunde genau das, was das OP schon mit nativen Versprechungen gemacht hat. – Bergi

+0

Ähnlich, außer dass er eine Zeitüberschreitung von 10 ms anstelle einer Zeitüberschreitung von 10 Sekunden anwendete. Persönlich bevorzuge ich Bluebird Versprechungen. Das Äquivalent zu Bluebird-Versprechen zu machen erfordert etwas zusätzliche Aufmerksamkeit für Details und es gibt eine Menge Möglichkeiten für menschliche Fehler. – arboreal84

+0

Ja, ich auch. Aber solange Sie einen solchen Fehler nicht finden und auf Details hinweisen, die anders funktionieren, löst diese Antwort das Problem nicht. – Bergi

0

Wie Bergi erwähnt, müssen Sie die connection.break Methode verwenden.

die folgende Funktion gegeben:

create or replace function wait_for_seconds(
    p_seconds in number 
) 
    return number 
is 
begin 
    dbms_lock.sleep(p_seconds); 

    return 1; 
end; 

Hier ist ein Beispiel für seine Verwendung:

const oracledb = require('oracledb'); 
const config = require('./dbConfig.js'); 
let conn; 
let err; 
let timeout; 

oracledb.getConnection(config) 
    .then((c) => { 
    conn = c; 

    timeout = setTimeout(() => { 
     console.log('Timeout expired, invoking break'); 

     conn.break((err) => { 
     console.log('Break finished', err); 
     }); 
    }, 5000); 

    return conn.execute(
    `select wait_for_seconds(10) 
     from dual`, 
     [], 
     { 
     outFormat: oracledb.OBJECT 
     } 
    ); 
    }) 
    .then(result => { 
    console.log(result.rows); 

    clearTimeout(timeout); 
    }) 
    .catch(err => { 
    console.log('Error in processing', err); 

    if (/^Error: ORA-01013/.test(err)) { 
     console.log('The error was related to the timeout'); 
    } 
    }) 
    .then(() => { 
    if (conn) { // conn assignment worked, need to close 
     return conn.close(); 
    } 
    }) 
    .catch(err => { 
    console.log('Error during close', err) 
    }); 

Beachten Sie, dass der setTimeout Anruf kurz vor dem Ausführen ist (wegen der return-Anweisung). Dieser Timeout beginnt sofort mit dem Countdown. Es wird jedoch nicht garantiert, dass der Ausführungsaufruf sofort gestartet wird, da er einen Thread aus dem Thread-Pool verwendet und möglicherweise warten muss, bis einer verfügbar ist. Nur etwas im Auge zu behalten ...