From 9d0971bf43ff38ae79b52704f862d1f016cedb9c Mon Sep 17 00:00:00 2001 From: Damian Zehnder Date: Thu, 19 Oct 2023 11:18:42 +0200 Subject: [PATCH 1/6] feat: create wrapper for SQSClient --- .gitignore | 1 + src/index.js | 12 ++++++------ src/sqs-queue.js | 28 +++++++++++----------------- src/sqs-wrapper.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 src/sqs-wrapper.js diff --git a/.gitignore b/.gitignore index 4562b131..76f81824 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ logs test-results.xml .env .idea/ +.npmrc diff --git a/src/index.js b/src/index.js index d0c80753..47d99b7b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ /* - * Copyright 2019 Adobe. All rights reserved. + * Copyright 2023 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -13,9 +13,9 @@ import secrets from '@adobe/helix-shared-secrets'; import wrap from '@adobe/helix-shared-wrap'; import { logger } from '@adobe/helix-universal-logger'; import { helixStatus } from '@adobe/helix-status'; -import SQSQueue from './sqs-queue.js'; -import DB from './db.js'; // Assuming the exported content of './db' is default exported -import PSIClient from './psi-client.js'; // Assuming the exported content of './psi-client' is default exported +import DB from './db.js'; +import PSIClient from './psi-client.js'; +import { SQSWrapper } from './sqs-wrapper.js'; /** * This is the main function @@ -27,7 +27,6 @@ async function run(request, context) { const db = DB({ region: process.env.REGION, }); - const sqsQueue = SQSQueue(); const { message } = JSON.parse(context.invocation.event.Records[0].body); const psiClient = PSIClient({ @@ -44,11 +43,12 @@ async function run(request, context) { }; const auditResult = await psiClient.runAudit(`https://${site.domain}/${site.path}`); const auditResultMin = await db.saveAuditIndex(site, auditResult); - await sqsQueue.sendMessage(auditResultMin); + await context.sqsQueue.sendMessage(auditResultMin); return new Response('SUCCESS'); } export const main = wrap(run) + .with(SQSWrapper) .with(helixStatus) .with(logger.trace) .with(logger) diff --git a/src/sqs-queue.js b/src/sqs-queue.js index 0278c8b5..fb84d460 100644 --- a/src/sqs-queue.js +++ b/src/sqs-queue.js @@ -9,47 +9,41 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs'; +import { SendMessageCommand } from '@aws-sdk/client-sqs'; +import { log } from './util.js'; // Set up the region const REGION = 'us-east-1'; // change this to your desired region -// Create SQS service client object -const sqsClient = new SQSClient({ region: REGION }); - // Your SQS queue URL const queueURL = 'https://sqs.us-east-1.amazonaws.com/282898975672/spacecat-audit-results'; -function SQSQueue() { +function SQSQueue(sqsClient, queueUrl) { async function sendMessage(message) { const body = { message, timestamp: new Date().toISOString(), }; - // Set up the parameters for the send message command const params = { DelaySeconds: 10, MessageBody: JSON.stringify(body), - QueueUrl: queueURL, + QueueUrl: queueUrl, }; try { const data = await sqsClient.send(new SendMessageCommand(params)); - console.log('Success, message sent. MessageID:', data.MessageId); + log('info', 'Success, message sent. MessageID:', data.MessageId); + return { + statusCode: 200, + body: JSON.stringify({ message: 'SQS message sent!' }), + }; } catch (err) { - console.log('Error:', err); + log('error', 'Error:', err); throw err; } - - return { - statusCode: 200, - body: JSON.stringify({ message: 'SQS message sent!' }), - }; } - return { - sendMessage, - }; + return { sendMessage }; } export default SQSQueue; diff --git a/src/sqs-wrapper.js b/src/sqs-wrapper.js new file mode 100644 index 00000000..6ddcebc8 --- /dev/null +++ b/src/sqs-wrapper.js @@ -0,0 +1,45 @@ +/* + * Copyright 2023 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +'use strict'; + +import { SQSClient } from '@aws-sdk/client-sqs'; +import { log } from './util.js'; +import SqsQueue from './sqs-queue.js'; + +let sqsClient; + +function SQSWrapper(func) { + return async (request, context) => { + const region = process.env.AWS_REGION; + const queueUrl = process.env.QUEUE_URL; + + if (!region) { + throw new Error('region is required'); + } + if (!queueUrl) { + throw new Error('queueUrl is required'); + } + + // Initialize the SQSClient only if it hasn't been initialized yet + if (!sqsClient) { + log('info', `Creating SQS client in region ${region}`); + sqsClient = new SQSClient({ region }); + } + + context.sqsQueue = SqsQueue(sqsClient, queueUrl); + + return func(request, context); + }; +} + +export default SQSWrapper; From 83e34ce1e2708f06e165c9ef18a9f1983cd4f3db Mon Sep 17 00:00:00 2001 From: Damian Zehnder Date: Thu, 19 Oct 2023 14:42:19 +0200 Subject: [PATCH 2/6] fix: PR review --- src/index.js | 8 +++--- src/{sqs-wrapper.js => queue-wrapper.js} | 23 +++++------------ src/sqs-queue.js | 26 ++++++++----------- src/util.js | 33 ------------------------ 4 files changed, 22 insertions(+), 68 deletions(-) rename src/{sqs-wrapper.js => queue-wrapper.js} (60%) delete mode 100644 src/util.js diff --git a/src/index.js b/src/index.js index 47d99b7b..5257af4a 100644 --- a/src/index.js +++ b/src/index.js @@ -15,7 +15,7 @@ import { logger } from '@adobe/helix-universal-logger'; import { helixStatus } from '@adobe/helix-status'; import DB from './db.js'; import PSIClient from './psi-client.js'; -import { SQSWrapper } from './sqs-wrapper.js'; +import { queueWrapper } from './queue-wrapper.js'; /** * This is the main function @@ -43,13 +43,13 @@ async function run(request, context) { }; const auditResult = await psiClient.runAudit(`https://${site.domain}/${site.path}`); const auditResultMin = await db.saveAuditIndex(site, auditResult); - await context.sqsQueue.sendMessage(auditResultMin); + await context.queue.sendAuditResult(auditResultMin); return new Response('SUCCESS'); } export const main = wrap(run) - .with(SQSWrapper) .with(helixStatus) .with(logger.trace) .with(logger) - .with(secrets); + .with(secrets) + .with(queueWrapper); diff --git a/src/sqs-wrapper.js b/src/queue-wrapper.js similarity index 60% rename from src/sqs-wrapper.js rename to src/queue-wrapper.js index 6ddcebc8..2437e06f 100644 --- a/src/sqs-wrapper.js +++ b/src/queue-wrapper.js @@ -12,34 +12,25 @@ 'use strict'; -import { SQSClient } from '@aws-sdk/client-sqs'; -import { log } from './util.js'; import SqsQueue from './sqs-queue.js'; -let sqsClient; - -function SQSWrapper(func) { +function queueWrapper(func) { return async (request, context) => { const region = process.env.AWS_REGION; - const queueUrl = process.env.QUEUE_URL; + const queueUrl = process.env.AUDIT_RESULTS_QUEUE_URL; + const { log } = context; if (!region) { - throw new Error('region is required'); + throw new Error('AWS_REGION env variable is empty/not provided'); } if (!queueUrl) { - throw new Error('queueUrl is required'); - } - - // Initialize the SQSClient only if it hasn't been initialized yet - if (!sqsClient) { - log('info', `Creating SQS client in region ${region}`); - sqsClient = new SQSClient({ region }); + throw new Error('AUDIT_RESULTS_QUEUE_URL env variable is empty/not provided'); } - context.sqsQueue = SqsQueue(sqsClient, queueUrl); + context.queue = SqsQueue(region, queueUrl, log); return func(request, context); }; } -export default SQSWrapper; +export default queueWrapper; diff --git a/src/sqs-queue.js b/src/sqs-queue.js index fb84d460..4d5c27bf 100644 --- a/src/sqs-queue.js +++ b/src/sqs-queue.js @@ -9,17 +9,17 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import { SendMessageCommand } from '@aws-sdk/client-sqs'; -import { log } from './util.js'; +import { SendMessageCommand, SQSClient } from '@aws-sdk/client-sqs'; -// Set up the region -const REGION = 'us-east-1'; // change this to your desired region +let sqsClient; -// Your SQS queue URL -const queueURL = 'https://sqs.us-east-1.amazonaws.com/282898975672/spacecat-audit-results'; +function SQSQueue(region, queueUrl, log) { + if (!sqsClient) { + sqsClient = new SQSClient({ region }); + log.info(`Creating SQS client in region ${region}`); + } -function SQSQueue(sqsClient, queueUrl) { - async function sendMessage(message) { + async function sendAuditResult(message) { const body = { message, timestamp: new Date().toISOString(), @@ -33,17 +33,13 @@ function SQSQueue(sqsClient, queueUrl) { try { const data = await sqsClient.send(new SendMessageCommand(params)); - log('info', 'Success, message sent. MessageID:', data.MessageId); - return { - statusCode: 200, - body: JSON.stringify({ message: 'SQS message sent!' }), - }; + log.info('Success, message sent. MessageID:', data.MessageId); } catch (err) { - log('error', 'Error:', err); + log.error('Error:', err); throw err; } } - return { sendMessage }; + return { sendAuditResult }; } export default SQSQueue; diff --git a/src/util.js b/src/util.js deleted file mode 100644 index b2c184ad..00000000 --- a/src/util.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2023 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -const log = (level, message, ...args) => { - const timestamp = new Date().toISOString(); - - switch (level) { - case 'info': - console.info(`[${timestamp}] INFO: ${message}`, ...args); - break; - case 'error': - console.error(`[${timestamp}] ERROR: ${message}`, ...args); - break; - case 'warn': - console.warn(`[${timestamp}] WARN: ${message}`, ...args); - break; - default: - console.log(`[${timestamp}] ${message}`, ...args); - break; - } -}; - -export { - log, -}; From 2f903852602f462003707fd3590c5a0730c83a19 Mon Sep 17 00:00:00 2001 From: Damian Zehnder Date: Thu, 19 Oct 2023 14:47:54 +0200 Subject: [PATCH 3/6] fix: PR review --- src/index.js | 8 ++++---- src/queue-wrapper.js | 11 +++-------- src/sqs-queue.js | 4 +--- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/index.js b/src/index.js index 5257af4a..e54acfb7 100644 --- a/src/index.js +++ b/src/index.js @@ -15,7 +15,7 @@ import { logger } from '@adobe/helix-universal-logger'; import { helixStatus } from '@adobe/helix-status'; import DB from './db.js'; import PSIClient from './psi-client.js'; -import { queueWrapper } from './queue-wrapper.js'; +import queueWrapper from './queue-wrapper.js'; /** * This is the main function @@ -25,13 +25,13 @@ import { queueWrapper } from './queue-wrapper.js'; */ async function run(request, context) { const db = DB({ - region: process.env.REGION, + region: context.env.REGION, }); const { message } = JSON.parse(context.invocation.event.Records[0].body); const psiClient = PSIClient({ - apiKey: process.env.PAGESPEED_API_KEY, - baseUrl: process.env.PAGESPEED_API_BASE_URL, + apiKey: context.env.PAGESPEED_API_KEY, + baseUrl: context.env.PAGESPEED_API_BASE_URL, }); const site = { diff --git a/src/queue-wrapper.js b/src/queue-wrapper.js index 2437e06f..82b44973 100644 --- a/src/queue-wrapper.js +++ b/src/queue-wrapper.js @@ -14,15 +14,12 @@ import SqsQueue from './sqs-queue.js'; -function queueWrapper(func) { +export default function queueWrapper(func) { return async (request, context) => { - const region = process.env.AWS_REGION; - const queueUrl = process.env.AUDIT_RESULTS_QUEUE_URL; + const region = context.env.AWS_REGION; + const queueUrl = context.env.AUDIT_RESULTS_QUEUE_URL; const { log } = context; - if (!region) { - throw new Error('AWS_REGION env variable is empty/not provided'); - } if (!queueUrl) { throw new Error('AUDIT_RESULTS_QUEUE_URL env variable is empty/not provided'); } @@ -32,5 +29,3 @@ function queueWrapper(func) { return func(request, context); }; } - -export default queueWrapper; diff --git a/src/sqs-queue.js b/src/sqs-queue.js index 4d5c27bf..31a87520 100644 --- a/src/sqs-queue.js +++ b/src/sqs-queue.js @@ -13,7 +13,7 @@ import { SendMessageCommand, SQSClient } from '@aws-sdk/client-sqs'; let sqsClient; -function SQSQueue(region, queueUrl, log) { +export default function SQSQueue(region, queueUrl, log) { if (!sqsClient) { sqsClient = new SQSClient({ region }); log.info(`Creating SQS client in region ${region}`); @@ -41,5 +41,3 @@ function SQSQueue(region, queueUrl, log) { } return { sendAuditResult }; } - -export default SQSQueue; From 0cbdaa6684f670b55b721915018f9d1cf9b09148 Mon Sep 17 00:00:00 2001 From: Damian Zehnder Date: Thu, 19 Oct 2023 17:02:29 +0200 Subject: [PATCH 4/6] fix: secret wrapper at end --- src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index e54acfb7..d1b2db7c 100644 --- a/src/index.js +++ b/src/index.js @@ -51,5 +51,5 @@ export const main = wrap(run) .with(helixStatus) .with(logger.trace) .with(logger) - .with(secrets) - .with(queueWrapper); + .with(queueWrapper) + .with(secrets); From 71285f75336b256d54f140f421482653a8de5732 Mon Sep 17 00:00:00 2001 From: Damian Zehnder Date: Fri, 20 Oct 2023 15:34:17 +0200 Subject: [PATCH 5/6] feat: change SQS queue from functional to class component --- src/index.js | 8 +++++--- src/queue-wrapper.js | 4 ++-- src/sqs-queue.js | 32 +++++++++++++++++++++----------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/index.js b/src/index.js index d1b2db7c..dfe3e508 100644 --- a/src/index.js +++ b/src/index.js @@ -20,14 +20,16 @@ import queueWrapper from './queue-wrapper.js'; /** * This is the main function * @param {Request} request the request object (see fetch api) - * @param {UniversalContext} context the context of the universal serverless function + * @param {UniversalContext} context the context of the universal serverle ss function * @returns {Response} a response */ async function run(request, context) { const db = DB({ region: context.env.REGION, }); - const { message } = JSON.parse(context.invocation.event.Records[0].body); + const message = JSON.parse(context.invocation.event.Records[0].body); + console.error('###body', context.invocation.event.Records[0].body); + console.error('###message', message); const psiClient = PSIClient({ apiKey: context.env.PAGESPEED_API_KEY, @@ -49,7 +51,7 @@ async function run(request, context) { export const main = wrap(run) .with(helixStatus) + .with(queueWrapper) .with(logger.trace) .with(logger) - .with(queueWrapper) .with(secrets); diff --git a/src/queue-wrapper.js b/src/queue-wrapper.js index 82b44973..ccff8302 100644 --- a/src/queue-wrapper.js +++ b/src/queue-wrapper.js @@ -16,8 +16,8 @@ import SqsQueue from './sqs-queue.js'; export default function queueWrapper(func) { return async (request, context) => { - const region = context.env.AWS_REGION; - const queueUrl = context.env.AUDIT_RESULTS_QUEUE_URL; + const { region } = context.runtime; + const queueUrl = process.env.AUDIT_RESULTS_QUEUE_URL; const { log } = context; if (!queueUrl) { diff --git a/src/sqs-queue.js b/src/sqs-queue.js index 31a87520..2a3ff0d0 100644 --- a/src/sqs-queue.js +++ b/src/sqs-queue.js @@ -11,15 +11,24 @@ */ import { SendMessageCommand, SQSClient } from '@aws-sdk/client-sqs'; -let sqsClient; +/** + * @class SQSQueue class to send audit results to SQS + * @param {string} region - AWS region + * @param {string} queueUrl - SQS queue URL + * @param {object} log - OpenWhisk log object + */ +class SQSQueue { + constructor(region, queueUrl, log) { + if (!this.sqsClient) { + this.sqsClient = new SQSClient({ region }); + log.info(`Creating SQS client in region ${region}`); + } -export default function SQSQueue(region, queueUrl, log) { - if (!sqsClient) { - sqsClient = new SQSClient({ region }); - log.info(`Creating SQS client in region ${region}`); + this.queueUrl = queueUrl; + this.log = log; } - async function sendAuditResult(message) { + async sendAuditResult(message) { const body = { message, timestamp: new Date().toISOString(), @@ -28,16 +37,17 @@ export default function SQSQueue(region, queueUrl, log) { const params = { DelaySeconds: 10, MessageBody: JSON.stringify(body), - QueueUrl: queueUrl, + QueueUrl: this.queueUrl, }; try { - const data = await sqsClient.send(new SendMessageCommand(params)); - log.info('Success, message sent. MessageID:', data.MessageId); + const data = await this.sqsClient.send(new SendMessageCommand(params)); + this.log.info(`Success, message sent. MessageID: ${data.MessageId}`); } catch (err) { - log.error('Error:', err); + this.log.error(`Error: ${err}`); throw err; } } - return { sendAuditResult }; } + +export default SQSQueue; From a05ac6f526f57673efc13f3a55da8170b881426b Mon Sep 17 00:00:00 2001 From: Damian Zehnder Date: Fri, 20 Oct 2023 15:34:48 +0200 Subject: [PATCH 6/6] fix: class usage --- src/queue-wrapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queue-wrapper.js b/src/queue-wrapper.js index ccff8302..1565e96f 100644 --- a/src/queue-wrapper.js +++ b/src/queue-wrapper.js @@ -24,7 +24,7 @@ export default function queueWrapper(func) { throw new Error('AUDIT_RESULTS_QUEUE_URL env variable is empty/not provided'); } - context.queue = SqsQueue(region, queueUrl, log); + context.queue = new SqsQueue(region, queueUrl, log); return func(request, context); };