From 7233789f2a3ec8ea78487ada82ed7e52da164ce1 Mon Sep 17 00:00:00 2001 From: Aashish Dhakal <85501584+dhakalaashish@users.noreply.github.com> Date: Thu, 25 Apr 2024 16:30:30 +0545 Subject: [PATCH 1/2] Add logging to GOES-16 Provider --- .../ProviderClass/GOES16GeoEventProviderClass.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/server/src/Services/GeoEventProvider/ProviderClass/GOES16GeoEventProviderClass.ts b/apps/server/src/Services/GeoEventProvider/ProviderClass/GOES16GeoEventProviderClass.ts index cffc57b3..7359a3ac 100644 --- a/apps/server/src/Services/GeoEventProvider/ProviderClass/GOES16GeoEventProviderClass.ts +++ b/apps/server/src/Services/GeoEventProvider/ProviderClass/GOES16GeoEventProviderClass.ts @@ -8,6 +8,7 @@ import { type geoEventInterface as GeoEvent } from "../../../Interfaces/GeoEvent import {Confidence} from '../../../Interfaces/GeoEvent'; import {determineSlice} from "../../../utils/geometry" import ee from '@google/earthengine' +import {logger} from "../../../server/logger" type FireDataEntry = [number, number, Date]; type AllFireData = FireDataEntry[]; @@ -57,16 +58,19 @@ class GOES16GeoEventProviderClass implements GeoEventProviderClass { null, () => { console.log('Google Earth Engine authentication successful'); + logger(`Google Earth Engine authentication successful`, "info"); resolve(); }, (err) => { console.error('Google Earth Engine initialization error', err); + logger(`Google Earth Engine initialization error`, "error"); reject(err); } ); }, (err) => { console.error('Google Earth Engine authentication error', err); + logger(`Google Earth Engine authentication error`, "error"); reject(err); } ); @@ -135,12 +139,12 @@ class GOES16GeoEventProviderClass implements GeoEventProviderClass { } }); }) as FireDataEntry; - // Concatenate the current image's fire data with the master array allFireData = allFireData.concat(fireData); }; } catch (error) { console.error("Error fetching fire data:", error); + logger(`Error fetching fire data`, "error"); } // Normalize the fire data into GeoEvent format @@ -156,10 +160,10 @@ class GOES16GeoEventProviderClass implements GeoEventProviderClass { slice: determineSlice(fireData[1], fireData[0]), data: {'satellite': clientApiKey, 'slice': slice} })); - resolve(geoEventsData); } catch (error) { console.error('Failed to fetch or process GOES-16 data', error); + logger(`Failed to fetch or process GOES-16 data`, "error"); reject(error); } }); From 56489211fd69dc5550564dd772efa2d1917f25e1 Mon Sep 17 00:00:00 2001 From: Aashish Dhakal <85501584+dhakalaashish@users.noreply.github.com> Date: Fri, 26 Apr 2024 17:13:10 +0545 Subject: [PATCH 2/2] Refactor earthengine API calls for async handling and avoid EROFS errors - Implement promise-based async handling for ee.Date(...).getInfo() to align with Node.js async patterns and avoid implicit filesystem writes in Vercel's read-only environment. - Prevent EROFS: read-only file system errors by managing asynchronous flow explicitly, eliminating dependencies on synchronous requests or filesystem operations in serverless deployments. --- .../GOES16GeoEventProviderClass.ts | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/server/src/Services/GeoEventProvider/ProviderClass/GOES16GeoEventProviderClass.ts b/apps/server/src/Services/GeoEventProvider/ProviderClass/GOES16GeoEventProviderClass.ts index cffc57b3..ed46c1b9 100644 --- a/apps/server/src/Services/GeoEventProvider/ProviderClass/GOES16GeoEventProviderClass.ts +++ b/apps/server/src/Services/GeoEventProvider/ProviderClass/GOES16GeoEventProviderClass.ts @@ -8,6 +8,7 @@ import { type geoEventInterface as GeoEvent } from "../../../Interfaces/GeoEvent import {Confidence} from '../../../Interfaces/GeoEvent'; import {determineSlice} from "../../../utils/geometry" import ee from '@google/earthengine' +import {logger} from "../../../server/logger" type FireDataEntry = [number, number, Date]; type AllFireData = FireDataEntry[]; @@ -61,12 +62,14 @@ class GOES16GeoEventProviderClass implements GeoEventProviderClass { }, (err) => { console.error('Google Earth Engine initialization error', err); + logger(`Google Earth Engine initialization error`, "error"); reject(err); } ); }, (err) => { console.error('Google Earth Engine authentication error', err); + logger(`Google Earth Engine authentication error`, "error"); reject(err); } ); @@ -87,10 +90,6 @@ class GOES16GeoEventProviderClass implements GeoEventProviderClass { const fromDateTime = (!lastRunDate || (currentDateTime.getTime() - lastRunDate.getTime()) > 2 * 3600 * 1000) ? twoHoursAgo : lastRunDate; const images = ee.ImageCollection("NOAA/GOES/16/FDCF").filterDate(fromDateTime, currentDateTime); - - // Fetch and process images here... - // The process includes fetching image IDs, processing them to extract fire data, etc. - // This is a simplified outline; integrate the logic from your initial example here. const getImagesId = () => { return new Promise((resolve, reject) => { images.evaluate((imageCollection) => { @@ -98,20 +97,29 @@ class GOES16GeoEventProviderClass implements GeoEventProviderClass { const imagesData = imageCollection.features.map(feature => feature.id); resolve(imagesData); } else { + logger('No features found in image collection', 'error'); reject(new Error("No features found")); } }); }); }; + const getDateTimeInfo = (image) => { + return new Promise((resolve, reject) => { + ee.Date(image.get('system:time_start')).getInfo((info, error) => { + if (error) { + reject(error); + return; + } + resolve(info); + }); + }); + } try { const array_imagesId = await getImagesId() as string[]; for (const imageId of array_imagesId) { const image = ee.Image(`${imageId}`) - // Get the datetime information from the image metadata - const datetimeInfo = await ee.Date(image.get('system:time_start')).getInfo(); + const datetimeInfo = await getDateTimeInfo(image); const datetime = new Date(datetimeInfo.value); - - const temperatureImage = image.select('Temp'); const xMin = -142; // On station as GOES-E const xMax = xMin + 135; @@ -135,12 +143,12 @@ class GOES16GeoEventProviderClass implements GeoEventProviderClass { } }); }) as FireDataEntry; - // Concatenate the current image's fire data with the master array allFireData = allFireData.concat(fireData); }; } catch (error) { console.error("Error fetching fire data:", error); + logger(`Error fetching fire data: ${error}`, "error"); } // Normalize the fire data into GeoEvent format @@ -160,6 +168,7 @@ class GOES16GeoEventProviderClass implements GeoEventProviderClass { resolve(geoEventsData); } catch (error) { console.error('Failed to fetch or process GOES-16 data', error); + logger(`Failed to fetch or process GOES-16 data`, "error"); reject(error); } });