0

I have a method in nodejs used to generate a document. If I have two simultaneous requests, the content of one document is the same as the second one (the variable "contents" below). If for example the source.content retrieved by the first request should be "aaa" and the second is "bbb", the actual content of the file is "aaa" in both cases. If the requests are run sequentially, the content of the generated file is correct, "aaa" for the first request and "bbb" for the second.

public async generateDocument(req: Request, res: Response) {

        const sourceId = parseInt(req.params.id, 10);
        const source: ISource = await this.db.models.MoM.scope("full").findOne({ where: { sourceId : sourceId } });

        const signatureDate = getDateNow();
        // Load the docx file as a binary
        const content = fs.readFileSync(path.resolve(__dirname, "../../../../assets/Template.docx"), "binary");
        const zip = new PizZip(content);
        const doc = new Docxtemplater();
        doc.loadZip(zip);
        doc.setData({

            // @ts-ignore TODO: fix generic interfaces
            writer_name: "" + source.writer.displayedName,
            contents: source.content.split("\n").map((paragraph: string) => ({
                paragraph,
            })),

        });
        doc.render();
        const buf = doc.getZip().generate({ type: "nodebuffer" });
        const outputFilePath = path.resolve(__dirname, "../../../../assets/output.docx");
        fs.writeFileSync(outputFilePath, buf);
}
  • The way a database does this is locking the table until the first request is done, only then the second request is allowed to something with the table – The Fool Jul 21 '20 at 11:05
  • It's not changing anything in the database. It only generates a document based on an information from the database. The problem is that the information belongs to a different request. – topProgrammer Jul 21 '20 at 13:08
  • I told you the way a database handles it. Not go and do something with your database. You would have to apply the same design pattern to your files. Lock them while they are being accessed. – The Fool Jul 21 '20 at 17:32
  • Does this answer your question? [How can I lock a file while writing to it asynchronously](https://stackoverflow.com/questions/35616281/how-can-i-lock-a-file-while-writing-to-it-asynchronously) – The Fool Jul 21 '20 at 17:33
  • 1
    Yes, locking the file solves the problem, thanks! – topProgrammer Aug 12 '20 at 10:43

1 Answers1

0

In your code, you do, at the end of the function

const outputFilePath = path.resolve(__dirname, "../../../../assets/output.docx");
fs.writeFileSync(outputFilePath, buf);

Which means that if the function is called twice, there is no way to know whether the generated file will be from the first call or the second call.

Probably, somewhere in your code, you are reading the /assets/output.docx file.

To solve your problem, I would instead return a Buffer from the generateDocument function, like this :

public async generateDocument(req: Request, res: Response) {
        // ...
        // ...
        doc.render();
        const buf = doc.getZip().generate({ type: "nodebuffer" });
        return buf;
}

And the caller of generateDocument should serve the buffer or do something with that (no need to write the file on the filesystem if you just want to let the user download it rightaway for example).

edi9999
  • 19,701
  • 13
  • 88
  • 127