2016-03-30 5 views
0

Der folgende Code nie im Stich gelassen hat, wenn in dev auf OSX laufen, aber jedes Mal in einer Produktionsumgebung nicht, die in einem Docker Behälter lebt:fs.readFile Behaving Unterschiedlich Innerhalb Docker Container

DataSyncController.js

let jsonFile = await FileSystemService.ParseCsvToJson(fileName); 
if (!jsonFile.success) 
     return res.json({ success: false }); 

let parsedJson = await FileSystemService.ParseJsonFile({ file: jsonFile.fileName }); 
if (!parsedJson.success) 
    return res.json({ success: false }); 

FileSystemService.js

static async ParseJsonFile(params) 
{ 
    return new Promise((resolve, reject) => 
    { 
     try 
     { 
      fs.readFile(jsonFilePath, 'utf-8', (err, data) => 
      { 
       if (err) 
       { 
        console.log('fs.readFile() error: ', err); 
        resolve({ success: false }); 
       } 

       var file = []; 

       try 
       { 
        // This fails every time in the Docker container 
        // Error is [Unexpected end of input] 
        // At this point I've seend `data` evaluate to '', 
        // <buffer >, undefined and partial JSON data 
        file = JSON.parse(data); 
       } 
       catch(e) 
       { 
        console.log('ERROR parsing JSON file: ', e); 
        return resolve({ success: false }); 
       } 

       // Do Stuff 
       return resolve({ success: true }); 
      }); 
     } 
     catch(exception) 
     { 
      console.error(exception); 
      resolve({ success: false }); 
     } 
    }); 
} 

Es sieht so aus, als würde die JSON-Datei im Docker-Container nicht geschrieben werden, wenn sie gelesen wird (zB dass JSON.parse() funktioniert, wenn ich den ganzen fs.readFile() Block in eine timeout lege und verhindere, dass sie für 5 Sekunden läuft), aber ich nicht Sehen Sie, wie das möglich ist und warum es im Docker-Container und nicht auf meinem lokalen Rechner der Fall sein würde. Alle Gedanken werden wie immer sehr geschätzt.

aktualisiert

Wie gewünscht, hier ist die Umsetzung der ParseCsvToJson Methode, die tatsächlich die JSON-Datei auf der Festplatte schreibt. Beachten Sie, dass sowohl in Entwicklung und Produktion im Docker-Container, die geschriebene JSON-Datei, während groß (ca. 4.400 Datensätze), gut aussieht.

var Converter = require("csvtojson").Converter; 
var filePath = `${config.root}/server/uploadDir`; 

static async ParseCsvToJson(fileName) 
{ 
    return new Promise((resolve, reject) => 
    { 
     try 
     { 
      let fileNameWithoutExtension = fileName.replace('.csv', ''); 
      const jsonFilePath = `${filePath}/${fileNameWithoutExtension}.json`; 
      const csvFilePath = `${filePath}/${fileName}`; 

      // The parameter false will turn off final result construction. 
      // It can avoid huge memory consumption while parsing. 
      // The trade off is final result will not be populated to end_parsed event. 
      var csvConverter = new Converter({ constructResult: false, toArrayString: true }); 
      var readStream = fs.createReadStream(csvFilePath); 
      var writeStream = fs.createWriteStream(jsonFilePath); 
      readStream.pipe(csvConverter).pipe(writeStream); 

      resolve({ success: true, fileName: `${fileNameWithoutExtension}.json` }); 
     } 
     catch(exception) 
     { 
      console.error(exception); 
      resolve({ success: false }); 
     } 
    }); 
} 
+0

Ich bin ziemlich sicher, dass Ihre 'ParseJsonFile()' Funktion sollte ablehnen, anstatt mit "success = false" zu lösen. – Tomalak

+1

Ja, das ist eigentlich auf meiner Liste zu ändern. Ich hatte einen Grund dafür, aber ich erinnere mich ehrlich gesagt nicht daran, was das im Moment war. – MyCompassSpins

+0

Zeigen Sie auch die Implementierung von 'ParseCsvToJson'. (Ich nehme an, dass dieser, trotz seines schrulligen Namens, tatsächlich die JSON-Datei schreibt, also vermute ich den Fehler dort) – Tomalak

Antwort

0

Dies war ein Ergebnis sowohl ein Mangel an Verständnis dafür, wie Linux befasst sich mit streams/Rohren und einem falschen Verständnis der Dokumentation für das csvtojson Modul. In Bezug auf die Instanziierung des Wandlers:

var csvConverter = new Converter({ constructResult: false, toArrayString: true }); 

Die docs sagen:

Der Parameter falsch wird Endergebnis Bau auszuschalten. Es kann große Speicherverbrauch beim Parsen vermeiden. Der Trade-Off ist das Endergebnis wird nicht bis zum Ereignis end_parsed aufgefüllt.

Aus Gründen mich nicht wirklich verstehen, auf OSX, ist dies ausreichend:

var readStream = fs.createReadStream('path/to/csvfile.csv', { encoding: 'utf-8' }); 
var writeStream = fs.createWriteStream('path/to/jsonfile.json', { encoding: 'utf-8' }); 
readStream.pipe(csvConverter).pipe(writeStream); 
resolve({ success: true, fileName: '.json' }); 

Während auf einem Linux-System, die Datei überhaupt nicht immer vollständig geschrieben oder geschrieben ist. Daher wird die folgende erforderlich:

csvConverter.on('end_parsed',() => 
{ 
    // The docs are unclear whether there is a possible error object 
    // passed along here in the case of failure, but clearly mention 
    // that the constructed result will be unavailable, so just resolve 
    // the Promise 
    resolve({ success: true, fileName: 'jsonfile.json' }); 
}); 

Dies ist ein Rand Fall sein kann, aber hoffentlich wird es jemand anderes in der Zukunft helfen.