Skip to content

Commit 079fefa

Browse files
committed
Merge remote-tracking branch 'origin'
Adding tunable parameters for data export.
2 parents cf84cf5 + cafddaa commit 079fefa

5 files changed

Lines changed: 37 additions & 5 deletions

File tree

src/API/.envrc.template

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
3939
export DATA_TEMPLATES_FOLDER="$SCRIPT_DIR/templates"
4040
export FULL_OCCURRENCE_DATA_FOLDER="$SCRIPT_DIR/../OccurrenceGeoJob/.tmp/target" # Set to value of TARGET_DIRECTORY of OccurrenceGeoJob. Ensure job has been ran first.
4141
export DATABASE_GUIDE_FILE_NAME="Vector_Atlas_Database_Guide.pdf" # Must be located inside the '$DATA_TEMPLATES_FOLDER/Vector Atlas'
42+
export DATA_EXPORT_BATCH_SIZE=200 # Tune the batch size based on deployment environment.
43+
export DATA_EXPORT_YIELD_AFTER=5 # After how many batches should setImmediate be called. May be useful for giving node time to clean-up memory and process other requests.

src/API/src/config/config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ const config = convict({
6060
default: 'Vector_Atlas_Database_Guide.pdf',
6161
env: 'DATABASE_GUIDE_FILE_NAME',
6262
},
63+
dataExportBatchSize: {
64+
type: Number,
65+
doc: 'The max batch size (number of rows) during data export. Tune based on observed deployment environment factors e.g, database/network latency higher give node more room to be idle thus memory pressure is low.',
66+
default: 200,
67+
env: 'DATA_EXPORT_BATCH_SIZE',
68+
},
69+
dataExportYieldAfter: {
70+
type: Number,
71+
doc: 'After how many batches should setImmediate be called. May be useful for giving node time to clean-up memory and process other requests',
72+
default: 5,
73+
env: 'DATA_EXPORT_YIELD_AFTER',
74+
},
6375
});
6476

6577
export default config;

src/API/src/db/shared/dynamic-export.service-v2.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ export class DynamicExportServiceV2<T = Occurrence> {
167167
columns: RawTemplateFieldMap[],
168168
targetFilePath: string | null = null,
169169
pageSize = 200,
170+
yieldAfter = 5,
170171
exportJob: ExportJob = null,
171172
updateProgressCallback?: (jobId: string, progress: number) => void,
172173
saveToDisk = true,
@@ -179,6 +180,8 @@ export class DynamicExportServiceV2<T = Occurrence> {
179180
fs.mkdirSync(exportDir, { recursive: true });
180181
}
181182

183+
console.log('Using pageSize of', pageSize);
184+
182185
const finalPath =
183186
targetFilePath ||
184187
path.join(exportDir, `va_export_${exportJob?.id || Date.now()}.xlsx`);
@@ -258,9 +261,9 @@ export class DynamicExportServiceV2<T = Occurrence> {
258261
updateProgressCallback(exportJob.id, progress);
259262
}
260263

261-
// yield every 5 pages (~1,000 rows)
264+
// yield every x pages
262265
// Potentially gives other HTTP requests and health checks an immediate turn on the event loop
263-
if (page % 5 === 0) {
266+
if (page % yieldAfter === 0) {
264267
await new Promise((resolve) => setImmediate(resolve));
265268
}
266269
}

src/API/src/exports/exports.processor-v2.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
RAW_TEMPLATE_FIELD_EXCLUDED,
1515
RAW_TEMPLATE_FIELD_MAPPING,
1616
} from 'src/db/occurrence/template-mapping';
17-
import { extractFileNameFromBlobUrl } from 'src/utils';
17+
import { extractFileNameFromBlobUrl, maskEmail } from 'src/utils';
1818

1919
@Injectable()
2020
@Processor('exports')
@@ -94,7 +94,8 @@ export class ExportsProcessorV2 extends WorkerHost {
9494
JSON.stringify(sanitizedFilters),
9595
);
9696

97-
const take = 200;
97+
const take = config.get('dataExportBatchSize');
98+
const yieldAfter = config.get('dataExportYieldAfter');
9899
const saveToDisk = true; // CRITICAL: Forces ExcelJS streaming writer to write straight to disk
99100

100101
// 2. STREAM EXCEL DIRECTLY TO DISK
@@ -103,6 +104,7 @@ export class ExportsProcessorV2 extends WorkerHost {
103104
RAW_TEMPLATE_FIELD_MAPPING,
104105
excelFilePath, // Output file target
105106
take,
107+
yieldAfter,
106108
exportJob,
107109
(jobId, progress) => {
108110
this.exportsService.updateProgress(jobId, progress);
@@ -200,7 +202,9 @@ export class ExportsProcessorV2 extends WorkerHost {
200202
);
201203

202204
console.log(
203-
`Notification email sent to ${updatedExportJob.downloaderEmail}`,
205+
`Notification email sent to ${maskEmail(
206+
updatedExportJob.downloaderEmail,
207+
)}`,
204208
);
205209
}
206210

src/API/src/utils.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ import { sanitize } from './dataset-upload/utils';
33
import path from 'path';
44
import { isKeyObject } from 'util/types';
55

6+
import crypto from 'crypto';
7+
8+
export function maskEmail(email: string) {
9+
if (!email || typeof email !== 'string') return 'unknown-user';
10+
11+
return crypto
12+
.createHash('sha256')
13+
.update(email.trim().toLowerCase())
14+
.digest('hex');
15+
}
16+
617
export const isEmpty = (object) =>
718
Object.values(object).every((x) => x === null || x === '' || x === undefined);
819

0 commit comments

Comments
 (0)