2016-07-12 5 views
1

Ich schreibe ein ETL-Tool, das mit einer Oracle-Datenbank interagiert, die auch node-oracledb1.10 und RxJS verwendet, um alle verschiedenen asynchronen Datenströme zu behandeln, die ich herumwerfen. Ich stoße auf ein Problem, wo je länger meine Anwendung läuft, desto länger dauert ein Anruf an node-oracledb 's .execute(), und es scheint in der Laufzeit linear zu erhöhen. Hoffentlich können Sie den Fehler im folgenden Code erkennen und korrigieren.Warum führt mein node-oracledb Promise immer schneller in der Zeit aus, die zur Lösung benötigt wird?

Lassen Sie mich zuerst zeigen, wie ich Oracle-Abfragen ausführen. Ich habe meine eigene Funktion erstellt, die als Wrapper um node-oracledb 's .execute() fungiert.

import oracledb from 'oracledb'; 
var oraConnPool; 

export function execute(sql, bind, opts) { 
    if (!oraConnPool) { 
    createOraPool(); 
    } 
    return oraConnPool 
    .then(pool => pool.getConnection()) 
    .then(conn => conn.execute(sql, bind, opts)); 
} 

function createOraPool() { 
    let oraPool = oracledb.createPool(config.database.oracle); 
    oraConnPool = oraPool; 
    return oraPool; 
} 

Und mein config.database.oracle (ohne die Anmeldeinformationen):

{ 
    "poolTimeout": 60, 
    "poolMin": 10, 
    "poolMax": 25, 
    "queueRequests": true, 
    "queueTimeout": 600000, 
    "_enableStats": true 
} 

Im Folgenden ist ein Beispiel für mich meine .execute() Funktion aufgerufen wird. Wie du sehen kannst, passiert hier sehr viel, also lass mich versuchen, es ein wenig zu kommentieren, um es zu verdeutlichen. rnd wird verwendet, um eine eindeutige ID für console.time() zu erstellen, damit ich die Zeit aufzeichnen kann, die für die Zeit benötigt. Lassen Sie mich wissen, ob es einen Fehler in dieser Zeitmessungstechnik gibt. Die bind-Eingabevariable, die an die SELECT-Anweisung übergeben wird, ist eine CSV-Zeichenfolge mit ssid-Bezeichnern, und eine Liste mit Übereinstimmungen wird zurückgegeben. Dadurch kann ich Datensätze im Stapel verarbeiten, anstatt für jede einzelne Zeile eine einzige Abfrage zu erstellen. Die erste macht jeden Schlüssel in dem resultierenden Array von Objekten in Kleinbuchstaben. Die zweite beendet natürlich die console.time() Verfolgung.

const rnd = Math.random() * 100; 
console.time(rnd); 
return execute(` 
    SELECT 
    ssid_input.ssid AS ssid, 
    students.id AS student_id, 
    students.student_number AS student_number 
    FROM (
     SELECT REGEXP_SUBSTR(
        :ssids, 
        '[^,]+', 1, level) AS ssid 
     FROM dual 
     CONNECT BY REGEXP_SUBSTR(
         :ssids, 
         '[^,]+', 1, level) IS NOT NULL 
) ssid_input 
    LEFT JOIN students ON students.state_studentnumber = ssid_input.ssid`, { 
    ssids: { 
     val: ssids.join(','), 
     dir: orawrap.BIND_IN, 
     type: orawrap.STRING 
    } 
    }, { 
    outFormat: orawrap.OBJECT, 
    maxRows: ssids.length 
    }) 
    .then(results => { 
    return results.rows.map(result => { 
     let newObj = {}; 
     Object.keys(result).forEach(key => { 
     newObj[key.toLowerCase()] = result[key]; 
     }); 
     return newObj; 
    }); 
    }) 
    .then(result => { 
    console.timeEnd(rnd); 
    return result; 
    }); 

Unten ist die console.time() Ausgabe, die stetig zunimmt, bis er die 60000 ms queueTimeout Grenze trifft.

97.24179652744425: 12226.930ms 
38.14057213652584: 14583.518ms 
46.19793585774834: 16024.785ms 
16.12600313565251: 17820.694ms 
87.73720584788988: 20809.461ms 
54.711100085462604: 22652.638ms 
42.474404414891744: 24037.868ms 
49.09845121453702: 26521.596ms 
87.70258724764568: 29461.480ms 
1.0731996619882223: 31210.875ms 
90.33430329792829: 32259.944ms 
37.4829457960367: 34076.824ms 
9.731832830291932: 35292.281ms 
/home/nathanjones/Projects/test-forge/node_modules/@reactivex/rxjs/dist/cjs/util/subscribeToResult.js:41 
      root_1.root.setTimeout(function() { throw err; }); 
               ^

Error: NJS-040: connection request timeout 

Ich habe versucht, den größten Teil des entsprechenden Codes enthalten, lassen Sie mich bitte wissen, wenn Sie mehr Kontext benötigen.

EDIT:

Ich habe eine console.log(pool._logStats()) Anweisung jedes Mal die .execute() Funktion aufgerufen wird. Ich habe den Ausgang der letzten Zeit enthalten sie vor dem NJS-040 Fehler gedruckt wurde:

Pool statistics: 
...total up time (milliseconds): 62823 
...total connection requests: 1794 
...total requests enqueued: 1769 
...total requests dequeued: 0 
...total requests failed: 0 
...total request timeouts: 0 
...max queue length: 1769 
...sum of time in queue (milliseconds): 0 
...min time in queue (milliseconds): 0 
...max time in queue (milliseconds): 0 
...avg time in queue (milliseconds): 0 
...pool connections in use: 25 
...pool connections open: 25 
Related pool attributes: 
...queueRequests: true 
...queueTimeout (milliseconds): 60000 
...poolMin: 10 
...poolMax: 25 
...poolIncrement: 1 
...poolTimeout (seconds): 60 
...stmtCacheSize: 30 
Related environment variables: 
...process.env.UV_THREADPOOL_SIZE: undefined 
undefined 

Antwort

3

Das in Issue 474 am Knoten-OracleDB repo diskutiert und analysiert wird.

Sie müssen sicherstellen, dass Sie die Verbindungen schließen.

Sie müssen wahrscheinlich UV_THREADPOOL_SIZE

erhöhen