Getting incomplete files when using Azure Functions
-
When I was testing the below on local (and calling a local jsreport), everything was working fine.
const axios = require("axios"); const express = require("express"); const router = express.Router(); const fs = require("fs"); const apiHelp = require("../../utf/common/apiReturnHelper"); router.use(function (req, res, next) { next(); }); router.post("/report", async function (req, res) { if (!req.session.currentUser){ return res.json(apiHelp.noSession()); } if (!req.body.data || !req.body.functionName){ return res.json(apiHelp.error({message:"missingData"})); } let data = req.body.data; let functionName = req.body.functionName; let unixTimeStamp = new Date().getTime() / 1000; //unix timestamp let fileName = unixTimeStamp + "_report.pdf"; let path = "temp/" + fileName; await fetchReport(path, data, functionName); fs.createReadStream(path).pipe(res).on('end', res.end); fs.access(path, fs.constants.R_OK, (err) => { console.log("\n> Checking Permission for reading the file"); if (err) console.error("No Read access"); else { setTimeout(()=> { fs.unlink(path, function (err) { if (err) { console.log("No file found"); } console.log("File deleted!");}) },3000);} }); }); var fetchReport = async (path, data, functionName) => { try { let jsr = process.env.JSREPORTURL + "/api/" + functionName; let options = { // auth: { user: 'admin', password: 'samer'}, url: jsr, //valid string to report api headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), responseType: "stream", maxContentLength: Infinity, maxBodyLength: Infinity, }; let response = await axios.post( jsr, { template: { name: "invoice" }, data: data, }, options ); let writeStream = response.data.pipe(fs.createWriteStream(path)) .on('finish', () => { console.log("DONE writing"); return; });; } catch (e) { console.log(e); } }; module.exports = router;
However, after deploying the jsreport app to Azure functions, here what's happening:
When I attempt to download my pdf file first time, it downloads fine:
However....when I call the same request for 2nd, 3rd time...etc, the pdf file is being incomplete and of course corrupt (can't open):
Notice how the file size is being smaller in the 2nd and 3rd time.
This is happening only on Azure Functions and not on local, however the reports being downloaded to the temp folder in backend are being fine.
I dunno what I am doing wrong, I feel the may be a delay issue from Azure Functions and sending file before finishing the read stream?
-
I solved it by wraping the fetchReport function with new Promise, after doing some logging I realized that the fetchReprot (which has the write stream) is finishing before sending the file to client:
var fetchReport = (path, data, functionName) => { return new Promise(async resolve => { let jsr = process.env.JSREPORTURL + "/api/" + functionName; let options = { // auth: { user: 'admin', password: 'samer'}, url: jsr, //valid string to report api headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), responseType: "stream", maxContentLength: Infinity, maxBodyLength: Infinity, }; let response = await axios.post( jsr, { template: { name: "invoice" }, data: data, }, options ); let writeStream = response.data.pipe(fs.createWriteStream(path)) .on('finish', () => { console.log("ONE"); resolve(writeStream); }) }) };
But I am not sure why it works, I thought that a Async function should behave like a function returning a new Promise?