Skip to content

Commit 93e1cce

Browse files
committed
Fixing OOM error in new-updates source component
1 parent 82e768c commit 93e1cce

File tree

3 files changed

+120
-13
lines changed

3 files changed

+120
-13
lines changed

components/google_sheets/sources/common/new-updates.mjs

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,21 @@ export default {
2020
label: "Worksheet ID(s)",
2121
description: "Select one or more worksheet(s), or provide an array of worksheet IDs.",
2222
},
23+
maxRows: {
24+
type: "integer",
25+
label: "Max Rows to Monitor",
26+
description: "Maximum number of rows to monitor for changes. Defaults to 10000. Increase with caution as larger values may cause memory issues.",
27+
optional: true,
28+
default: 10000,
29+
},
2330
},
2431
methods: {
32+
getBatchSize() {
33+
return 1000; // Process 1000 rows at a time
34+
},
35+
getMaxRows() {
36+
return this.maxRows || 10000;
37+
},
2538
getMeta(spreadsheet, worksheet) {
2639
const {
2740
sheetId: worksheetId,
@@ -56,6 +69,9 @@ export default {
5669
getWorksheetIds() {
5770
return this.worksheetIDs.map((i) => i.toString());
5871
},
72+
_getBatchKey(baseId, batchIndex) {
73+
return `${baseId}_batch_${batchIndex}`;
74+
},
5975
_getSheetValues(id) {
6076
const stringBuffer = this.db.get(id);
6177

@@ -72,6 +88,51 @@ export default {
7288
const stringBuffer = compressed.toString("base64");
7389
this.db.set(id, stringBuffer);
7490
},
91+
_getBatchedSheetValues(baseId) {
92+
const allValues = [];
93+
let batchIndex = 0;
94+
let hasMore = true;
95+
96+
while (hasMore) {
97+
const batchKey = this._getBatchKey(baseId, batchIndex);
98+
const batchValues = this._getSheetValues(batchKey);
99+
100+
if (!batchValues) {
101+
hasMore = false;
102+
break;
103+
}
104+
105+
allValues.push(...batchValues);
106+
batchIndex++;
107+
}
108+
109+
return allValues.length > 0
110+
? allValues
111+
: null;
112+
},
113+
_setBatchedSheetValues(baseId, sheetValues) {
114+
const batchSize = this.getBatchSize();
115+
const maxRows = this.getMaxRows();
116+
117+
// Limit to maxRows
118+
const limitedValues = sheetValues.slice(0, maxRows);
119+
120+
// Clear old batches first
121+
let batchIndex = 0;
122+
while (this.db.get(this._getBatchKey(baseId, batchIndex))) {
123+
this.db.set(this._getBatchKey(baseId, batchIndex), undefined);
124+
batchIndex++;
125+
}
126+
127+
// Store in batches
128+
batchIndex = 0;
129+
for (let i = 0; i < limitedValues.length; i += batchSize) {
130+
const batch = limitedValues.slice(i, i + batchSize);
131+
const batchKey = this._getBatchKey(baseId, batchIndex);
132+
this._setSheetValues(batchKey, batch);
133+
batchIndex++;
134+
}
135+
},
75136
indexToColumnLabel(index) {
76137
let columnLabel = "";
77138
while (index >= 0) {
@@ -133,10 +194,8 @@ export default {
133194
},
134195
async getContentDiff(spreadsheet, worksheet) {
135196
const sheetId = this.getSheetId();
136-
const oldValues =
137-
this._getSheetValues(
138-
`${spreadsheet.spreadsheetId}${worksheet.properties.sheetId}`,
139-
) || null;
197+
const baseId = `${spreadsheet.spreadsheetId}${worksheet.properties.sheetId}`;
198+
const oldValues = this._getBatchedSheetValues(baseId) || null;
140199
const currentValues = await this.googleSheets.getSpreadsheetValues(
141200
sheetId,
142201
worksheet.properties.title,
@@ -169,9 +228,11 @@ export default {
169228
continue;
170229
}
171230

172-
const offsetLength = Math.max(values.length - offset, 0);
231+
const maxRows = this.getMaxRows();
232+
const offsetLength = Math.max(Math.min(values.length, maxRows) - offset, 0);
173233
const offsetValues = values.slice(0, offsetLength);
174-
this._setSheetValues(`${sheetId}${worksheetId}`, offsetValues);
234+
const baseId = `${sheetId}${worksheetId}`;
235+
this._setBatchedSheetValues(baseId, offsetValues);
175236
}
176237
},
177238
async processSpreadsheet(spreadsheet) {
@@ -191,8 +252,11 @@ export default {
191252
spreadsheet,
192253
worksheet,
193254
);
194-
const newValues = currentValues.values || [];
255+
const maxRows = this.getMaxRows();
256+
const rawNewValues = currentValues.values || [];
257+
const newValues = rawNewValues.slice(0, maxRows);
195258
let changes = [];
259+
196260
// check if there are differences in the spreadsheet values
197261
if (JSON.stringify(oldValues) !== JSON.stringify(newValues)) {
198262
let rowCount = this.getRowCount(newValues, oldValues);
@@ -214,10 +278,8 @@ export default {
214278
this.getMeta(spreadsheet, worksheet),
215279
);
216280
}
217-
this._setSheetValues(
218-
`${spreadsheet.spreadsheetId}${worksheet.properties.sheetId}`,
219-
newValues || [],
220-
);
281+
const baseId = `${spreadsheet.spreadsheetId}${worksheet.properties.sheetId}`;
282+
this._setBatchedSheetValues(baseId, newValues || []);
221283
}
222284
},
223285
},

components/google_sheets/sources/new-updates-polling/new-updates-polling.mjs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export default {
2020
intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
2121
},
2222
},
23+
// eslint-disable-next-line pipedream/props-label, pipedream/props-description
24+
alert: {
25+
type: "alert",
26+
alertType: "info",
27+
content: "**Important**: If your sheet has more than 1000 rows, please set the **Monitoring Range** below to avoid performance issues and potential disruptions. Example: `A1:Z1000` to monitor the first 1000 rows with columns A through Z.",
28+
},
2329
watchedDrive: {
2430
propDefinition: [
2531
googleSheets,
@@ -36,11 +42,50 @@ export default {
3642
}),
3743
],
3844
},
39-
...common.props,
45+
worksheetIDs: {
46+
propDefinition: [
47+
googleSheets,
48+
"worksheetIDs",
49+
(c) => ({
50+
sheetId: c.sheetID,
51+
}),
52+
],
53+
type: "integer[]",
54+
label: "Worksheet ID(s)",
55+
description: "Select one or more worksheet(s), or provide an array of worksheet IDs.",
56+
},
57+
monitoringRange: {
58+
type: "string",
59+
label: "Monitoring Range",
60+
description: "The A1 notation range to monitor for changes (e.g., `A1:B100` or `Sheet1!A1:Z1000`). If not specified, the entire sheet will be monitored up to 10000 rows. **Recommended for sheets with more than 1000 rows**.",
61+
optional: true,
62+
},
4063
},
4164
methods: {
4265
...base.methods,
4366
...common.methods,
67+
getMonitoringRange() {
68+
return this.monitoringRange;
69+
},
70+
async getContentDiff(spreadsheet, worksheet) {
71+
const sheetId = this.getSheetId();
72+
const baseId = `${spreadsheet.spreadsheetId}${worksheet.properties.sheetId}`;
73+
const oldValues = this._getBatchedSheetValues(baseId) || null;
74+
75+
// Use monitoring range if specified, otherwise use worksheet title
76+
const range = this.monitoringRange
77+
? this.monitoringRange
78+
: worksheet.properties.title;
79+
80+
const currentValues = await this.googleSheets.getSpreadsheetValues(
81+
sheetId,
82+
range,
83+
);
84+
return {
85+
oldValues,
86+
currentValues,
87+
};
88+
},
4489
},
4590
hooks: {
4691
async deploy() {

components/google_sheets/sources/new-updates/new-updates.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default {
99
type: "source",
1010
name: "New Updates (Instant)",
1111
description: "Emit new event each time a row or cell is updated in a spreadsheet.",
12-
version: "0.3.3",
12+
version: "0.3.4",
1313
dedupe: "unique",
1414
props: {
1515
...httpBase.props,

0 commit comments

Comments
 (0)