Skip to content

Commit

Permalink
feat(core): append channel to kv key to make it channel aware (#1075)
Browse files Browse the repository at this point in the history
* feat(core): append channel to kv key to make it channel aware

* fix: move namespace logic to kvKey

* fix: version const
  • Loading branch information
jorgemoya committed Jul 9, 2024
1 parent 2faed17 commit 4bf7d16
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-hotels-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": patch
---

Append channel to kv keys.
25 changes: 8 additions & 17 deletions core/lib/kv/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,11 @@ const memoryKv = new MemoryKvAdapter();
class KV<Adapter extends KvAdapter> implements KvAdapter {
private kv?: Adapter;
private memoryKv = memoryKv;
private namespace: string;

constructor(
private createAdapter: () => Promise<Adapter>,
private config: Config = {},
) {
this.namespace =
process.env.KV_NAMESPACE ??
`${process.env.BIGCOMMERCE_STORE_HASH ?? 'store'}_${
process.env.BIGCOMMERCE_CHANNEL_ID ?? '1'
}`;
}
) {}

async get<Data>(key: string) {
const [value] = await this.mget<Data>(key);
Expand All @@ -31,26 +24,25 @@ class KV<Adapter extends KvAdapter> implements KvAdapter {

async mget<Data>(...keys: string[]) {
const kv = await this.getKv();
const fullKeys = keys.map((key) => `${this.namespace}_${key}`);

const memoryValues = (await this.memoryKv.mget<Data>(...fullKeys)).filter(Boolean);
const memoryValues = (await this.memoryKv.mget<Data>(...keys)).filter(Boolean);

if (memoryValues.length === keys.length) {
this.logger(
`MGET - Keys: ${fullKeys.toString()} - Value: ${JSON.stringify(memoryValues, null, 2)}`,
`MGET - Keys: ${keys.toString()} - Value: ${JSON.stringify(memoryValues, null, 2)}`,
);

return memoryValues;
}

const values = await kv.mget<Data>(...fullKeys);
const values = await kv.mget<Data>(...keys);

this.logger(`MGET - Keys: ${fullKeys.toString()} - Value: ${JSON.stringify(values, null, 2)}`);
this.logger(`MGET - Keys: ${keys.toString()} - Value: ${JSON.stringify(values, null, 2)}`);

// Store the values in memory kv
await Promise.all(
values.map(async (value, index) => {
const key = fullKeys[index];
const key = keys[index];

if (!key) {
return;
Expand All @@ -69,11 +61,10 @@ class KV<Adapter extends KvAdapter> implements KvAdapter {
opts?: Options,
) {
const kv = await this.getKv();
const fullKey = `${this.namespace}_${key}`;

this.logger(`SET - Key: ${fullKey} - Value: ${JSON.stringify(value, null, 2)}`);
this.logger(`SET - Key: ${key} - Value: ${JSON.stringify(value, null, 2)}`);

await Promise.all([this.memoryKv.set(fullKey, value, opts), kv.set(fullKey, value, opts)]);
await Promise.all([this.memoryKv.set(key, value, opts), kv.set(key, value, opts)]);

return value;
}
Expand Down
10 changes: 9 additions & 1 deletion core/lib/kv/keys.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
const VERSION = 'v3';

export const STORE_STATUS_KEY = 'storeStatus';
export const routeCacheKvKey = (pathname: string) => `v3_${pathname}`;

export const kvKey = (key: string, channelId?: string) => {
const namespace = process.env.KV_NAMESPACE ?? process.env.BIGCOMMERCE_STORE_HASH ?? 'store';
const id = channelId ?? process.env.BIGCOMMERCE_CHANNEL_ID ?? '1';

return `${namespace}_${id}_${VERSION}_${key}`;
};
11 changes: 6 additions & 5 deletions core/middlewares/with-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { graphql } from '~/client/graphql';
import { getRawWebPageContent } from '~/client/queries/get-raw-web-page-content';
import { getRoute } from '~/client/queries/get-route';
import { getStoreStatus } from '~/client/queries/get-store-status';
import { routeCacheKvKey, STORE_STATUS_KEY } from '~/lib/kv/keys';
import { kvKey, STORE_STATUS_KEY } from '~/lib/kv/keys';

import { defaultLocale, localePrefix, LocalePrefixes, locales } from '../i18n';
import { kv } from '../lib/kv';
Expand Down Expand Up @@ -76,7 +76,7 @@ const updateRouteCache = async (pathname: string, event: NextFetchEvent): Promis
expiryTime: Date.now() + 1000 * 60 * 30, // 30 minutes
};

event.waitUntil(kv.set(routeCacheKvKey(pathname), routeCache));
event.waitUntil(kv.set(kvKey(pathname, channelId), routeCache));

return routeCache;
};
Expand All @@ -95,7 +95,7 @@ const updateStatusCache = async (event: NextFetchEvent): Promise<StorefrontStatu
expiryTime: Date.now() + 1000 * 60 * 5, // 5 minutes
};

event.waitUntil(kv.set(STORE_STATUS_KEY, statusCache));
event.waitUntil(kv.set(kvKey(STORE_STATUS_KEY, channelId), statusCache));

return statusCache;
};
Expand All @@ -120,11 +120,12 @@ const clearLocaleFromPath = (path: string) => {

const getRouteInfo = async (request: NextRequest, event: NextFetchEvent) => {
try {
const channelId = getChannelIdFromLocale(locale);
const pathname = clearLocaleFromPath(request.nextUrl.pathname);

let [routeCache, statusCache] = await kv.mget<RouteCache | StorefrontStatusCache>(
routeCacheKvKey(pathname),
STORE_STATUS_KEY,
kvKey(pathname, channelId),
kvKey(STORE_STATUS_KEY, channelId),
);

// If caches are old, update them in the background and return the old data (SWR-like behavior)
Expand Down

0 comments on commit 4bf7d16

Please sign in to comment.