Skip to content

Commit 91f1bac

Browse files
authored
feat: store skus and last previewed in files storage (#23)
* feat: store skus and last previewed in files storage * fix tests
1 parent 51528b0 commit 91f1bac

File tree

4 files changed

+67
-48
lines changed

4 files changed

+67
-48
lines changed

actions/check-product-changes/index.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,17 @@ OF ANY KIND, either express or implied. See the License for the specific languag
1010
governing permissions and limitations under the License.
1111
*/
1212

13-
const { Core } = require('@adobe/aio-sdk');
14-
const { stateLib } = require('@adobe/aio-lib-state');
13+
const { Core, State, Files } = require('@adobe/aio-sdk');
1514
const { poll } = require('./poller');
1615
const { StateManager } = require('./lib/state');
1716

1817
async function main(params) {
19-
const state = await stateLib.init();
20-
2118
const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' });
22-
const stateMgr = new StateManager(state, { logger });
19+
const stateLib = await State.init();
20+
const filesLib = await Files.init();
21+
const stateMgr = new StateManager(stateLib, { logger });
2322

2423
const running = await stateMgr.get('running');
25-
2624
if (running?.value === 'true') {
2725
return { state: 'skipped' };
2826
}
@@ -32,7 +30,7 @@ async function main(params) {
3230
// this might not be updated and action execution could be permanently skipped
3331
// a ttl == function timeout is a mitigation for this risk
3432
await stateMgr.put('running', 'true', 3600);
35-
return await poll(params, state);
33+
return await poll(params, filesLib);
3634
} finally {
3735
await stateMgr.put('running', 'false');
3836
}

actions/check-product-changes/poller.js

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,19 @@ const { GetAllSkusQuery, GetLastModifiedQuery } = require('../queries');
1717
const { Core } = require('@adobe/aio-sdk');
1818

1919
const BATCH_SIZE = 50;
20+
const FILE_PREFIX = 'check-product-changes';
21+
const FILE_EXT = 'txt';
2022

21-
async function loadState(locale, stateMgr) {
23+
function getFileLocation(stateKey) {
24+
return `${FILE_PREFIX}/${stateKey}.${FILE_EXT}`;
25+
}
26+
27+
async function loadState(locale, filesLib) {
2228
const stateKey = locale ? `${locale}` : 'default';
23-
const stateData = await stateMgr.get(stateKey);
24-
if (!stateData?.value) {
29+
const fileLocation = getFileLocation(stateKey);
30+
const buffer = await filesLib.read(fileLocation);
31+
const stateData = buffer?.toString();
32+
if (!stateData) {
2533
return {
2634
locale,
2735
skusLastQueriedAt: new Date(0),
@@ -32,7 +40,7 @@ async function loadState(locale, stateMgr) {
3240
// <timestamp>,<sku1>,<timestamp>,<sku2>,<timestamp>,<sku3>,...,<timestamp>
3341
// the first timestamp is the last time the SKUs were fetched from Adobe Commerce
3442
// folloed by a pair of SKUs and timestamps which are the last preview times per SKU
35-
const [catalogQueryTimestamp, ...skus] = stateData && stateData.value ? stateData.value.split(',') : [0];
43+
const [catalogQueryTimestamp, ...skus] = stateData.split(',');
3644
return {
3745
locale,
3846
skusLastQueriedAt: new Date(parseInt(catalogQueryTimestamp)),
@@ -42,17 +50,18 @@ async function loadState(locale, stateMgr) {
4250
};
4351
}
4452

45-
async function saveState(state, stateMgr) {
53+
async function saveState(state, filesLib) {
4654
let { locale } = state;
4755
if (!locale) {
4856
locale = 'default';
4957
}
5058
const stateKey = `${locale}`;
59+
const fileLocation = getFileLocation(stateKey);
5160
const stateData = [
5261
state.skusLastQueriedAt.getTime(),
5362
...Object.entries(state.skus).flatMap(([sku, lastPreviewedAt]) => [sku, lastPreviewedAt.getTime()]),
5463
].join(',');
55-
await stateMgr.put(stateKey, stateData);
64+
await filesLib.write(fileLocation, stateData);
5665
}
5766

5867
/**
@@ -72,7 +81,7 @@ async function saveState(state, stateMgr) {
7281
* @param {string} [params.HLX_STORE_URL] - The store's base URL.
7382
* @param {string} [params.HLX_LOCALES] - Comma-separated list of allowed locales.
7483
* @param {string} [params.LOG_LEVEL] - The log level.
75-
* @param {Object} stateMgr - The StateManager instance object.
84+
* @param {Object} filesLib - The files provider object.
7685
* @returns {Promise<Object>} The result of the polling action.
7786
*/
7887
function checkParams(params) {
@@ -107,7 +116,7 @@ function shouldProcessProduct(product) {
107116
return urlKey?.match(/^[a-zA-Z0-9-]+$/) && lastModifiedDate >= lastPreviewDate;
108117
}
109118

110-
async function poll(params, stateMgr) {
119+
async function poll(params, filesLib) {
111120
checkParams(params);
112121

113122
const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' });
@@ -144,7 +153,7 @@ async function poll(params, stateMgr) {
144153
const results = await Promise.all(locales.map(async (locale) => {
145154
const timings = new Timings();
146155
// load state
147-
const state = await loadState(locale, stateMgr);
156+
const state = await loadState(locale, filesLib);
148157
timings.sample('loadedState');
149158

150159
let context = { ...sharedContext };
@@ -222,7 +231,7 @@ async function poll(params, stateMgr) {
222231
counts.failed++;
223232
}
224233
}
225-
await saveState(state, stateMgr);
234+
await saveState(state, filesLib);
226235
}
227236

228237
timings.sample('publishedPaths');
@@ -251,7 +260,7 @@ async function poll(params, stateMgr) {
251260
await deleteBatch({ counts, batch, state, adminApi });
252261
}
253262
// save state after deletes
254-
await saveState(state, stateMgr);
263+
await saveState(state, filesLib);
255264
}
256265
} catch (e) {
257266
// in case the index doesn't yet exist or any other error
@@ -298,4 +307,4 @@ return {
298307
};
299308
}
300309

301-
module.exports = { poll, loadState, saveState };
310+
module.exports = { poll, loadState, saveState, getFileLocation };

test/__mocks__/files.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
class Files {
2+
internalStorage = {};
3+
4+
constructor(storageLatency = 500) {
5+
this.storageLatency = storageLatency;
6+
}
7+
8+
async read(fileLocation) {
9+
return new Promise((resolve) => {
10+
setTimeout(() => resolve(this.internalStorage[fileLocation]), this.storageLatency);
11+
});
12+
}
13+
14+
async write(fileLocation, fileData) {
15+
return new Promise((resolve) => {
16+
setTimeout(() => resolve(this.internalStorage[fileLocation] = fileData), this.storageLatency);
17+
});
18+
}
19+
}
20+
21+
module.exports = Files;

test/check-product-changes.test.js

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
11
const assert = require('node:assert/strict');
2-
const { loadState, saveState } = require('../actions/check-product-changes/poller.js');
3-
const { StateManager } = require('../actions/check-product-changes/lib/state.js');
4-
const { MockState } = require('./__mocks__/state.js');
5-
6-
7-
const logger = { debug: () => {}, info: () => {}, error: () => {} };
8-
9-
const createStateManager = () => {
10-
const stateLib = new MockState(0);
11-
return new StateManager(stateLib, logger);
12-
}
2+
const { loadState, saveState, getFileLocation } = require('../actions/check-product-changes/poller.js');
3+
const Files = require('./__mocks__/files.js');
134

145
describe('Poller', () => {
156
it('loadState returns default state', async () => {
16-
const stateMgr = createStateManager();
17-
const state = await loadState('uk', stateMgr);
7+
const filesLib = new Files(0);
8+
const state = await loadState('uk', filesLib);
189
assert.deepEqual(
1910
state,
2011
{
@@ -26,9 +17,9 @@ describe('Poller', () => {
2617
});
2718

2819
it('loadState returns parsed state', async () => {
29-
const stateMgr = createStateManager();
30-
await stateMgr.put('uk', '1,sku1,2,sku2,3,sku3,4');
31-
const state = await loadState('uk', stateMgr);
20+
const filesLib = new Files(0);
21+
await filesLib.write(getFileLocation('uk'), '1,sku1,2,sku2,3,sku3,4');
22+
const state = await loadState('uk', filesLib);
3223
assert.deepEqual(
3324
state,
3425
{
@@ -44,31 +35,31 @@ describe('Poller', () => {
4435
});
4536

4637
it('loadState after saveState', async () => {
47-
const stateMgr = createStateManager();
48-
await stateMgr.put('uk', '1,sku1,2,sku2,3,sku3,4');
49-
const state = await loadState('uk', stateMgr);
38+
const filesLib = new Files(0);
39+
await filesLib.write(getFileLocation('uk'), '1,sku1,2,sku2,3,sku3,4');
40+
const state = await loadState('uk', filesLib);
5041
state.skusLastQueriedAt = new Date(5);
5142
state.skus['sku1'] = new Date(5);
5243
state.skus['sku2'] = new Date(6);
53-
await saveState(state, stateMgr);
44+
await saveState(state, filesLib);
5445

55-
const serializedState = await stateMgr.get('uk');
56-
assert.equal(serializedState?.value, '5,sku1,5,sku2,6,sku3,4');
46+
const serializedState = await filesLib.read(getFileLocation('uk'));
47+
assert.equal(serializedState, '5,sku1,5,sku2,6,sku3,4');
5748

58-
const newState = await loadState('uk', stateMgr);
49+
const newState = await loadState('uk', filesLib);
5950
assert.deepEqual(newState, state);
6051
});
6152

6253
it('loadState after saveState with null storeCode', async () => {
63-
const stateMgr = createStateManager();
64-
await stateMgr.put('default', '1,sku1,2,sku2,3,sku3,4');
65-
const state = await loadState(null, stateMgr);
54+
const filesLib = new Files(0);
55+
await filesLib.write(getFileLocation('default'), '1,sku1,2,sku2,3,sku3,4');
56+
const state = await loadState(null, filesLib);
6657
state.skusLastQueriedAt = new Date(5);
6758
state.skus['sku1'] = new Date(5);
6859
state.skus['sku2'] = new Date(6);
69-
await saveState(state, stateMgr);
60+
await saveState(state, filesLib);
7061

71-
const serializedState = await stateMgr.get('default');
72-
assert.equal(serializedState?.value, '5,sku1,5,sku2,6,sku3,4');
62+
const serializedState = await filesLib.read(getFileLocation('default'));
63+
assert.equal(serializedState, '5,sku1,5,sku2,6,sku3,4');
7364
});
7465
});

0 commit comments

Comments
 (0)