Serverless framework WarmUp plugin not being called - aws-lambda

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:
...

Related

Converting Nestjs with graphql prisma to serverless, error starting up

I am having some trouble with converting Nestjs to serverless.
My tech stack is, Nestjs, Graphql and Prisma.
I have followed multiple guide buy to no avail, below are the tutorials I have follow.
https://nishabe.medium.com/nestjs-serverless-lambda-aws-in-shortest-steps-e914300faed5
https://github.com/lnmunhoz/nestjs-graphql-serverless
The error that i am facing.
It happens when i start to navigate to it. Example, http://localhost:3000/dev/graphql, I wanted to access the playground
The problem shows that serverless file is missing, but its there under src
This is my serverless.ts file inside src folder
import { NestFactory } from '#nestjs/core';
import { ExpressAdapter } from '#nestjs/platform-express';
import { Context, Handler } from 'aws-lambda';
import serverless from 'aws-serverless-express';
import express from 'express';
import { Server } from 'http';
import { AppModule } from './app.module';
export async function bootstrap() {
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const app = await NestFactory.create(AppModule, adapter);
await app.init();
return serverless.createServer(expressApp);
}
let cachedServer: Server;
export const handler: Handler = async (event: any, context: Context) => {
if (!cachedServer) {
const server = await bootstrap();
cachedServer = server;
return serverless.proxy(server, event, context);
} else {
return serverless.proxy(cachedServer, event, context);
}
};
And this is my serverless.yml file
service: laundry-api
provider:
name: aws
runtime: nodejs12.x
region: ap-southeast-1
stage: dev
profile: default # Config your AWS Profile
plugins:
- serverless-offline
functions:
index:
handler: src/serverless.handler
environment:
SLS_DEBUG: true
events:
- http:
path: graphql
method: any
cors: true
I have been cracking my head for hours on where is the problem, tried webpack too.
Would be greate if you guys can point me to the right direction
Thank you.

How to deploy next.js 9 to AWS Lambda without using Serverless Components

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;
})();

How to access the return value of a lambda in a another cloudformation resource?

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.

AWS Sam Local Environment Variables not available in process.env

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'
}

Can we create lambda function using grunt instead of amazon console?

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.

Resources