Issue:
When accessing an endpoint that is consuming a file through Multer, over a docker-compose network, I am periodically receiving an empty file. If I check the file size, it claims to be the correct size, however. I can detect this erroneous state by hashing the file and determining that it is empty, waiting a few seconds for what appears to be a data transfer to happen, and then I am able to access the file.
Expected:
I expect the file to be accessible when the code for my route/controller is hit.
Version Information:
Express 4.16.4
Multer 1.4.2
Node 12.10
Docker 19.03.2 (windows, running a node:alpine container)
Here is a code snippet showing how I am able to reproduce the problem:
var multerupload = multer({
dest: 'tmp/'
});
function getHash(data) {
return crypto
.createHash('md5')
.update(data)
.digest('hex');
}
/**
* @swagger
*
* /api/pdf:
* post:
* summary: Takes in a file and analyzes it to show an issue with Multer
* consumes:
* - multipart/form-data
* parameters:
* - in: formData
* name: form-file
* type: file
* responses:
* 200:
* description: Wrote hash information to node console
*/
router.post('/', multerupload.single('form-file'), async (req, res)=>{
let file = req.file; //req.files[0];
console.log('File Path - ' + file.path);
console.log('Multer File Size: ' + file.size);
const stats = fs.statSync(file.path);
console.log('FS File Size: ' + stats.size);
// Read the file and generate a Hash
fs.readFile(file.path, async function(err, data) {
if (err) console.log('Error 1');
var hash = getHash(data);
console.log(hash);
// File is blank, regardless of what the File Size says
if (hash == 'd41d8cd98f00b204e9800998ecf8427e') {
// Wait for file to actually copy
await new Promise(done => setTimeout(done, 3000));
// Attempt to read the file again and generate a hash
fs.readFile(file.path, function(err, data) {
if (err) console.log('Error 2');
console.log(getHash(data));
});
}
});
res.sendStatus(200);
});
My docker-compose.yml is using a briged network.
Running the code will periodically produce the following:
microservice_pdf | File Path - tmp/f27ee6bc70b05156d3642c6aecd3409d
microservice_pdf | Multer File Size: 127483
microservice_pdf | FS File Size: 127483
microservice_pdf | d41d8cd98f00b204e9800998ecf8427e
microservice_pdf | 93f1f1f43d30d69004f614fa21cd88a0
This shows that multer is allowing my routine to execute as if the file is accessibly, when it clearly is not. Multer should wait until the file data is completely accessible.
@bpetty-formfast I tried recreating the problem with curl clients passing nearly 10,000 requests putting it in for-loop and I used docker-compose to bring the server up.
How is your client looking like ? Are you making concurrent/parallel requests ?
If you are using concurrent clients, there is a chance of Race condition though I haven't tested it.
Thanks @HarshithaKP for looking into it. I am using a single client, Swagger-UI, but I can reproduce it with Postman, etc. Basically the first few times I send the request it goes through, and then it blows up due to this issue. I have removed my nginx gateway and removed my docker-compose bridged network that I explicitly setup (still creates a default bridged network). Still having the issue. If I run the image directly with docker, everything is fine. I think the issue has something to do with the bridged network in docker, and multer thinking the file has been transferred when it is hasn't. A coworker couldn't reproduce this either... so I will do some more investigating. For me, it is an often occurrence.
Going to close this issue for now until a reproducible example is available. As it stands now, there's not enough information here for someone to reliably reproduce the environment the OP was working with and it doesn't seem _directly_ related to multer
Most helpful comment
Thanks @HarshithaKP for looking into it. I am using a single client, Swagger-UI, but I can reproduce it with Postman, etc. Basically the first few times I send the request it goes through, and then it blows up due to this issue. I have removed my nginx gateway and removed my docker-compose bridged network that I explicitly setup (still creates a default bridged network). Still having the issue. If I run the image directly with docker, everything is fine. I think the issue has something to do with the bridged network in docker, and multer thinking the file has been transferred when it is hasn't. A coworker couldn't reproduce this either... so I will do some more investigating. For me, it is an often occurrence.