With the following AWS SAM template process.env is an empty object. I expect it to contain the environment variable from the template defined as dbURL.
AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Description: "An example RESTful service"
Resources:
ExampleFunction:
Type: "AWS::Serverless::Function"
Properties:
Runtime: "nodejs6.10"
Handler: "/dist/getTickets/index.handler"
Events:
RootDeveloperHub:
Type: "Api"
Properties:
Path: "/new"
Method: "any"
Environment:
Variables:
dbURL: "dbURL_Value"
handler
exports.handler = (event, context, callback) => {
// logs {}
console.log(process.env)
}
Things I've ruled out:
webpack react process.env always empty (windows 10) - I don't have a DefinePlugin configuration. I'm also using mac.
I should have tested the code I posted...
The handler works when it is set up as
exports.handler = (event, context, callback) => {
// logs {}
console.log(process.env)
}
The fix for my code was to add the following to my webpack config.
{
...
target: 'node'
}
Related
System Information
Strapi Version: 4.2.0-beta.2
Operating System: Mac OS Monterey
Node Version: v16.14.2
NPM Version: 8.5.4
Hello everybody,
Does anyone know how to set the APP_KEYS asynchronously?
My code is:
// index.ts
export default {
async register({ strapi }) {
const credentials = await getAwsSecrets();
strapi.config.set("server", {
host: credentials.HOST,
port: credentials.PORT,
app: {
keys: credentials.APP_KEYS,
},
});
}
}
// server.ts
export default ({ env }) => ({
host: env("HOST", "0.0.0.0"),
port: env.int("PORT", 1337),
app: {
keys: env.array("APP_KEYS"),
},
});
But this error is occurs:
debug: ⛔️ Server wasn't able to start properly.
error: Middleware "strapi::session": App keys are required. Please set app.keys in config/server.js (ex: keys: ['myKeyA', 'myKeyB'])
at instantiateMiddleware (node_modules/#strapi/strapi/lib/services/server/middleware.js:12:11)
at resolveMiddlewares (node_modules/#strapi/strapi/lib/services/server/middleware.js:56:18)
at registerApplicationMiddlewares (node_modules/#strapi/strapi/lib/services/server/register-middlewares.js:66:29)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Object.initMiddlewares (node_modules/#strapi/strapi/lib/services/server/index.js:99:7)
at async Strapi.bootstrap (node_modules/#strapi/strapi/lib/Strapi.js:436:5)
at async Strapi.load (node_modules/#strapi/strapi/lib/Strapi.js:448:5)
at async Strapi.start (node_modules/#strapi/strapi/lib/Strapi.js:196:9)
I would like to simply deploy my Next.js 9 to AWS Lambdas using just API Gateway in front and make a proxy to the static path pointing to S3, but the only available option (without having to write all the stuff from the scratch) is https://github.com/serverless-nextjs/serverless-next.js which is currently using a beta version of Serverless Components (very buggy and lack of control over resources created as it does not uses CloudFormation), also this SLS Component forces the user to use CloudFront which is not my need, I have PR environments created all the time and allocating CloudFront for that is just waste of time/money/resources.
I tried to use the old version of the plugin serverless-nextjs-plugin but it seems not to work with Next.js 9, it fails to create the Lambdas for .html generated pages.
Is there any light in the end of this tunnel?
https://github.com/serverless-nextjs/serverless-next.js/issues/296 by this issue it looks like there's no way to do that.
I managed to make it work
serverless.base.yml file:
service: my-app
provider:
name: aws
runtime: nodejs12.x
timeout: 10 # seconds
memorySize: 1792 # Mb
custom:
webpack:
packager: yarn
includeModules:
forceInclude:
- chalk
functions:
nextJsApp:
handler: server.handler
events:
- http: 'ANY /'
- http: 'ANY {proxy+}'
server.js:
const { parse } = require('url');
const next = require('next');
const serverless = require('serverless-http');
const app = next({
dev: false
});
const requestHandler = app.getRequestHandler();
export const handler = serverless(async (req, res) => {
const parsedUrl = parse(req.url, true);
await requestHandler(req, res, parsedUrl);
});
wepback.config.js:
const CopyWebpackPlugin = require('copy-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
module.exports = {
...
externals: [nodeExternals()],
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: '.next', to: '.next' },
{ from: 'public', to: 'public' }
]
})
]
};
and here is the trick for working with serverless and webpack, use a serverless.js that modifies the serverless.base.yml and add all dependencies to the required dependencies to be included in the bundle:
const yaml = require('yaml-boost');
const minimist = require('minimist');
const path = require('path');
module.exports = (() => {
const params = minimist(process.argv.slice(2));
const serverless = yaml.load(path.join(__dirname, 'serverless.base.yml'), params);
const packageJson = require(path.join(__dirname, 'package.json'));
const dependencies = Object.keys(packageJson.dependencies);
serverless.custom.webpack.includeModules.forceInclude.push(...dependencies);
return serverless;
})();
I tried to integrate the WarmUp serverless plugin into my project. However, I believe that it is not working. I see no invocations from WarmUp in the lambda’s CloudWatch log group, and lambda does need warmup time after being idle for a bit.
My configuration is below:
service: ${file(./${env:DEPLOY_FILE_NAME}):service}
provider:
name: aws
custom:
roleName: ${file(./${env:DEPLOY_FILE_NAME_STAGE}):roleName}
profileName: ${file(./${env:DEPLOY_FILE_NAME_STAGE}):profileName}
bundle:
ignorePackages:
- pg-native
warmup:
enabled: true
events:
- schedule: rate(5 minutes)
prewarm: true
plugins:
- pluginHandler
- serverless-plugin-warmup
runtime: nodejs12.x
iamRoleStatements:
- Effect: 'Allow'
Action:
- 'lambda:InvokeFunction'
Resource:
- Fn::Join:
- ':'
- - arn:aws:lambda
- Ref: AWS::Region
- Ref: AWS::AccountId
- function:${self:service}-${opt:stage, self:provider.stage}-*
cfLogs: true
stage: ${file(./${env:DEPLOY_FILE_NAME_STAGE}):stage}
region: ${file(./${env:DEPLOY_FILE_NAME_STAGE}):region}
memorySize: ${file(./${env:DEPLOY_FILE_NAME_STAGE}):memorySize}
timeout: ${file(./${env:DEPLOY_FILE_NAME_STAGE}):timeout}
keepWarm: false
useApigateway: true
package:
exclude:
${file(./${env:DEPLOY_FILE_NAME}):exclude}
functions:
lambdaHandler:
handler: ${file(./${env:DEPLOY_FILE_NAME_STAGE}):handler}
events:
${file(./${env:DEPLOY_FILE_NAME}):events}
warmup:
enabled: true
The lambda code:
const awsLambdaFastify = require('aws-lambda-fastify');
const app = require('./index');
const proxy = awsLambdaFastify(app);
const fastify = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
proxy(event, context, callback);
};
const warm = func => (event, context, callback) => {
if (event.source === 'serverless-plugin-warmup') {
return callback(null, 'Lambda is warm!');
}
return func(event, context, callback);
};
exports.handler = warm(fastify);
Is there something that I could check? Any suggestions/directions are greatly appreciated.
Thank you
First of all, please move out the plugins from provider
plugins:
- serverless-plugin-warmup
provider:
...
GetClientId:
Type: "AWS::Lambda::Function"
Properties:
Handler: index.handler
Role: !GetAtt LambdaESCognitoRole.Arn
Code:
ZipFile: !Sub |
var AWS = require('aws-sdk');
const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
var response = require('cfn-response');
var responseData = {};
exports.handler = async (event, context) => {
console.log(JSON.stringify(event, null, 2));
var params = {
UserPoolId: event.ResourceProperties.UserPoolId
};
await cognitoidentityserviceprovider.listUserPoolClients(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else {
console.log(data); // successful response
responseData = {'ClientId': data.UserPoolClients[0].ClientId};
}
}).promise();
response.send(event, context, response.SUCCESS, responseData);
return;
}
Runtime: nodejs8.10
CallGetClientId:
Type: 'Custom::CallGetClientId'
Version: 1.0
Properties:
ServiceToken: !GetAtt GetClientId.Arn
UserPoolId: !Ref CognitoUserPool
IdentityPoolRoleMapping:
Type: "AWS::Cognito::IdentityPoolRoleAttachment"
Properties:
IdentityPoolId: !Ref CognitoIdentityPool
Roles:
authenticated: !GetAtt AuthenticatedRole.Arn
unauthenticated: !GetAtt UnauthenticatedRole.Arn
RoleMappings:
"cognito-identity-provider":
IdentityProvider: !Join ['', [ !GetAtt CognitoUserPool.ProviderName, ':', !GetAtt CallGetClientId.ClientId ]] #Need to get the ClientID here
AmbiguousRoleResolution: Deny
Type: Rules
RulesConfiguration:
Rules:
- Claim: "custom:groups"
MatchType: "Contains"
RoleARN: !GetAtt AuthenticatedRole.Arn
Value: "user"
- Claim: "custom:groups"
MatchType: "Contains"
RoleARN: !GetAtt AuthenticatedAdminRole.Arn
Value: "admin"
I see two ways to resolve the issue.
One - use the cfnresponse.send(...responseData) parameter. See here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html#w2ab1c17c25c14b9c11
My example:
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, responseData['ClientSecret'])
Once you returned data from Lambda, you can refer to it in CFN template with !GetAtt:
Value: !GetAtt HapiUserPoolClientPostProc.ClientSecret
Two - I use custom resources as a components "post-processor", i.e. create the resources, and update their parameters with a custom resource after. This order will be guaranteed by custom resource lambda input parameters (dependency).
My example was to feed in Cognito AppClient callback URLs from my ElasticBeanstalk WebApp. So I create both the UserPool AppClient and the EB webapp, then a post-processor custom resource lambda takes the URL from EB and updates the CallbackURL in Cognito.
Hope this helps.
I am creating a zip file for deployment to lambda using https://github.com/Tim-B/grunt-aws-lambda but when deploying to aws lambda I need to create the function first in amazon console. Can we create a function using grunt instead of amazon console? Thank you.
You can create the function from grunt using AWS JavaScript SDK for Lambda.
Use the createFunction method as shown below.
/* This example creates a Lambda function. */
var params = {
Code: {
},
Description: "",
FunctionName: "MyFunction",
Handler: "souce_file.handler_name", // is of the form of the name of your source file and then name of your function handler
MemorySize: 128,
Publish: true,
Role: "arn:aws:iam::123456789012:role/service-role/role-name", // replace with the actual arn of the execution role you created
Runtime: "nodejs4.3",
Timeout: 15,
VpcConfig: {
}
};
lambda.createFunction(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
/*
data = {
CodeSha256: "",
CodeSize: 123,
Description: "",
FunctionArn: "arn:aws:lambda:us-west-2:123456789012:function:MyFunction",
FunctionName: "MyFunction",
Handler: "source_file.handler_name",
LastModified: "2016-11-21T19:49:20.006+0000",
MemorySize: 128,
Role: "arn:aws:iam::123456789012:role/service-role/role-name",
Runtime: "nodejs4.3",
Timeout: 123,
Version: "1",
VpcConfig: {
}
}
*/
});
Note: You can fill the code parameter with code or use addition attributes to refer a code zipped and uploaded to S3.
E.g.
Code: { /* required */
S3Bucket: 'STRING_VALUE',
S3Key: 'STRING_VALUE',
S3ObjectVersion: 'STRING_VALUE',
ZipFile: new Buffer('...') || 'STRING_VALUE'
},
Also make sure to give required permission to the IAM User and setup JavaScript SDK credentials to run the code.