Search code examples
javascriptnode.jsnode-archiver

dynamically zip generated pdf files node-archiver


I'm trying to create multiple PDF file using pdfkit, I have an array of users and I create a report for each one, the createTable()Function below returns a Buffer that I send to archiver to zip, once complete the zip file is sent for download to the front end.

My issue is that for some reason, Archiver will sometimes throw a QUEUECLOSED error, if I run the function too many time, sometimes I can run it 10 times and the 11th time I'll get an error and sometimes I get an error after the second time, each time i run it the data is the same and nothing else changed.

Any help is greatly appreciated.

users.forEach(async (worker, index) => {
    createTable(date, worker.associateName, action, worker.email, worker.id, excahngeRate).then(resp => {
        archive.append(resp, { name: worker.associateName + '.pdf' })
        if (index === users.length - 1 === true) {//make sure its the last item in array
            archive.pipe(output)
            archive.finalize();
        }
    }).catch(err => {
        console.log(err)
    })
});

Solution

  • You finalize too soon. The createTable for the last user might not be the last to finish. You should add all to archive and once everything is done, finalize it.

    // Use map to get an array of promises
    const promises = users.map(async (worker, index) => {
        return createTable(date, worker.associateName, action, worker.email, worker.id, excahngeRate).then(resp => {
            archive.append(resp, { name: worker.associateName + '.pdf' })
        }).catch(err => {
            console.log(err)
        })
    });
    
    // Wait for all promises to finish.
    Promise.all(promises).then(()=>{
        archive.pipe(output)
        archive.finalize();
    });
    

    In your current code, you could console.log just before your IF statement, and log the index of the completed createTable, you'll see they do not finish in order.