Open DanielStout5 opened 2 years ago
Using zip-stream
directly instead of archiver
fixed this for me.
I created my own function:
zipAppend(zip, data, opts) {
return new Promise((resolve) => {
zip.entry(data, opts, (err) => {
if (err) {
console.log("zipAppend error", err);
if (!opts.ignoreError) throw err;
}
resolve();
});
});
},
Which, if opts.ignoreError is true, will just continue on if an error occurs, including if the S3 file isn't found.
This may not be perfect, but this is what we ended up doing:
import Archiver from "archiver/lib/core";
import {Logger} from "@nestjs/common";
import Zip from "archiver/lib/plugins/zip";
/***
* This class extends the base Archiver class in order to catch a KeyNotFound error from S3.
*/
export class RArchiver extends Archiver {
private readonly logger = new Logger(RArchiver.name, { timestamp: true });
constructor() {
super();
const zip = Zip({ store: true });
this.setModule(zip);
}
append(input, data) {
super.append(input, data);
}
pipe(response) {
super.pipe(response);
}
on(event: string, eventFunc) {
super.on(event, eventFunc);
}
setModule(zip: Zip) {
super.setModule(zip);
}
finalize() {
super.finalize();
}
// override to not emit error
_moduleAppend(source, data, callback) {
// @ts-ignore
if (this._state.aborted) {
callback();
return;
}
// @ts-ignore
this._module.append(source, data, function (err) {
this._task = null;
if (this._state.aborted) {
this._shutdown();
return;
}
// !! Handle error here !!
if (err) {
// Original handling code
// this.emit('error', err);
// Log error
this.logger.error(err);
setImmediate(callback);
return;
}
/**
* Fires when the entry's input has been processed and appended to the archive.
*
* @event Archiver#entry
* @type {EntryData}
*/
this.emit('entry', data);
this._entriesProcessedCount++;
if (data.stats && data.stats.size) {
this._fsEntriesProcessedBytes += data.stats.size;
}
/**
* @event Archiver#progress
* @type {ProgressData}
*/
this.emit('progress', {
entries: {
total: this._entriesCount,
processed: this._entriesProcessedCount
},
fs: {
totalBytes: this._fsEntriesTotalBytes,
processedBytes: this._fsEntriesProcessedBytes
}
});
setImmediate(callback);
}.bind(this));
}
}
This seems to be related to https://github.com/archiverjs/node-archiver/issues/252 and possibly https://github.com/archiverjs/node-archiver/issues/321
I'm downloading files from S3 and appending them to the archive.
Some of these files might not exist, and I'd prefer not to have to check whether they exist before trying to add to the archive (both for performance, to avoid an unnecessary check, and for reliability, since the file could be deleted in between the check and the download).
It seems like this should be handled by just adding an event handler for the "error" event:
That does log the error, but it does not continue with the other files. Is there another way to get basically "Continue on error" behavior?