My problem appears only sometimes(what is really strange) while saving multiple files simultaneously to cloud storage. I am using [google-cloud/storage](https://www.npmjs.com/package/@google-cloud/storage) library version 6.9.5.
I was able to find out people having the same issue however none of their solutions worked for me(neither changing stream options nor applying timeout). Firstly I thought that bandwidth could be exceeded, however I am almost sure we are not saving over 50Gb of data(I tried to check it using cloud charts; however you can check bandwidth usage only if other services are using cloud storage - in my case i get "No data available").
For further explanation:
In my code there is a function called "uploadFileToGCS" which is invoked around 57 times per each process. Process includes saving 35jpg(20KB per one) images, 1 tiff image(500KB) and 7 json(150KB per one) file. Simoultaneously 30 processes are invoked.
Here is exactly what error says:
error - unhandledRejection: FetchError: request to https://storage.googleapis.com/upload/storage/v1/b/satellite-photos/o?uploadType=multipart&name=64d162a80103b55f87a6cdb4_64db59204f7cd1f34a65e5c7_2023_6_31_raw.tiff failed, reason: read ECONNRESET
at ClientRequest.<anonymous> (D:\WORK\nirby-project\node_modules\next\dist\compiled\node-fetch\index.js:1:65756)
at ClientRequest.emit (node:events:525:35)
at TLSSocket.socketErrorListener (node:_http_client:496:9)
at TLSSocket.emit (node:events:513:28)
at emitErrorNT (node:internal/streams/destroy:151:8)
at emitErrorCloseNT (node:internal/streams/destroy:116:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
type: 'system',
errno: 'ECONNRESET',
code: 'ECONNRESET'
}
function saving 5 images(which is invoked 7 times in the same time):
saveLayers.ts:
import { saveSinglePhoto } from "~/helpers/sentinel/saveSinglePhoto";
interface INdviData {
min: number;
max: number;
averageNDVI: number;
buffer: Buffer;
}
const saveLayers = async (
fileNameBase: string,
trueColorData: Buffer,
ndviData: INdviData,
contrastNdviData: Buffer,
sclData: Buffer,
clmData: Buffer
) => {
console.log(fileNameBase);
const data = await Promise.all([
saveSinglePhoto(trueColorData, fileNameBase, "TRUECOLOR"),
saveSinglePhoto(ndviData.buffer, fileNameBase, "NDVI"),
saveSinglePhoto(contrastNdviData, fileNameBase, "CONTRAST_NDVI"),
saveSinglePhoto(sclData, fileNameBase, "SCL"),
saveSinglePhoto(clmData, fileNameBase, "CLM"),
]);
return data;
};
export default saveLayers;
saveSinglePhoto.ts
import { SatelliteData } from "~/interfaces/sentinel/SatelliteData";
import uploadFileToGCS from "../gcs/uploadFileToGCS";
const baseUrl = `https://storage.googleapis.com/${process.env.GCLOUD_STORAGE_BUCKET}/`;
export const saveSinglePhoto = async (
buffer: Buffer,
fileNameBase: string,
layerId: string
): Promise<SatelliteData | null> => {
const fileName = fileNameBase + layerId + ".jpg";
await uploadFileToGCS(fileName, buffer, "image/jpeg");
const satelliteData: SatelliteData = {
layerId: layerId,
fileUrl: baseUrl + fileName,
};
return satelliteData;
};
uploadFileToGCS.ts
import { Storage } from "@google-cloud/storage";
const gcsKey = JSON.parse(Buffer.from(process.env.GCLOUD_CRED_FILE, "base64").toString());
const storage = new Storage({
credentials: {
client_email: gcsKey.client_email,
private_key: gcsKey.private_key,
},
projectId: process.env.GCLOUD_PROJECT_ID,
});
const uploadFileToGCS = (filename: string, data: any, contentType: string) => {
return new Promise((resolve, reject) => {
const file = storage.bucket(process.env.GCLOUD_STORAGE_BUCKET).file(filename);
const stream = file.createWriteStream({
metadata: {
contentType,
},
resumable: false,
validation: false,
timeout: 86400,
});
stream.on("error", (err) => {
reject(err);
});
stream.on("finish", () => {
resolve("ok");
});
stream.end(data);
});
};
export default uploadFileToGCS;