Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: uu-per-item-counter-http-type #151

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion craft-functions/uu-per-item-counter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ Webサイト上で「いま何人がこの商品を見ています」と表示

## category

施策実装,CRAFT_ENDPOINT
施策実装,CRAFT_ENDPOINT

## functionType

http
38 changes: 24 additions & 14 deletions craft-functions/uu-per-item-counter/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { format, subMinutes } from 'date-fns';

const HOW_MANY_MINUTES_AGO = Number('<% HOW_MANY_MINUTES_AGO %>'); // 「最大何分前から現在まで」のUU数を集計するか?
const HOW_MANY_MINUTES_AGO = Number('<% HOW_MANY_MINUTES_AGO %>');
const COUNTER_KEY_PREFIX = '<% COUNTER_KEY_PREFIX %>';
const LOG_LEVEL = '<% LOG_LEVEL %>';
const TIMEWINDOW_FORMAT = 'yyyyMMddHHmm';
Expand All @@ -16,7 +16,7 @@ function counterKey({ timewindow, itemId }) {
*/
function makeTargetTimewindows() {
const targetTimewindows = [];
const agoArr = [...Array(HOW_MANY_MINUTES_AGO)].map((_, i) => i); // 3 -> [0, 1, 2]
const agoArr = [...Array(HOW_MANY_MINUTES_AGO)].map((_, i) => i);
agoArr.forEach(ago =>
targetTimewindows.push(format(subMinutes(new Date(), ago), TIMEWINDOW_FORMAT))
);
Expand Down Expand Up @@ -48,7 +48,7 @@ async function incrementCount({ counter, logger, itemId, currentTimewindow }) {
try {
await counter.increment({
key: counterKey({ timewindow: currentTimewindow, itemId }),
secondsToExpire: HOW_MANY_MINUTES_AGO * 60 + 60, // 参照されえないレコードは自動削除。60秒だけ余裕を持たせておく
secondsToExpire: HOW_MANY_MINUTES_AGO * 60 + 60,
});
logger.debug(`incrementCount succeeded. timewindow: ${currentTimewindow}. itemId: ${itemId}.`);
} catch (err) {
Expand All @@ -60,47 +60,57 @@ async function incrementCount({ counter, logger, itemId, currentTimewindow }) {

function noRequiredParamErr(param) {
return {
craft_status_code: 400,
statusCode: 400,
error: `"${param}" is required in the request body.`,
};
}

export default async function (data, { MODULES }) {
const { counter, initLogger } = MODULES;
const logger = initLogger({ logLevel: LOG_LEVEL });
const { req, res } = data;

if (data.kind !== 'karte/track-hook') {
logger.error(new Error('invalid kind. expected: karte/track-hook'));
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');

if (req.method === 'OPTIONS') {
res.status(204).end();
return;
}

const body = data.jsonPayload.data.hook_data.body;
const body = req.body;
if (typeof body !== 'object') {
return { craft_status_code: 400, error: 'Invalid request body.' };
res.status(400).json({ error: 'Invalid request body.' });
return;
}

const { itemId, skipIncrement, skipGettingCount } = body;
if (!itemId) return noRequiredParamErr('itemId');
if (!itemId) {
const { statusCode, error } = noRequiredParamErr('itemId');
res.status(statusCode).json({ error });
return;
}

const currentTimewindow = format(new Date(), TIMEWINDOW_FORMAT);
const targetTimewindows = makeTargetTimewindows(HOW_MANY_MINUTES_AGO);

logger.debug(`targetTimewindows: ${JSON.stringify(targetTimewindows)}`);

if (skipIncrement !== true) {
// getだけしたい場合はスキップ
await incrementCount({ counter, logger, itemId, currentTimewindow });
}

if (skipGettingCount === true) {
// incrementだけしたい場合はスキップ
return { craft_status_code: 200, count: null, error: null };
res.status(200).json({ count: null, error: null });
return;
}

const { statusCode, count, error } = await getCount({
counter,
logger,
itemId,
targetTimewindows,
});
return { craft_status_code: statusCode, count, error };
}
res.status(statusCode).json({ count, error });
}