SungardAS / lambda-formation

A small framework for building nodejs AWS Lambda projects that are compatible with AWS CloudFormation Custom Resources
Apache License 2.0
22 stars 4 forks source link

Sharing custom resource #13

Open estahn opened 7 years ago

estahn commented 7 years ago

Custom resources should be shareable/reusable via npm, e.g.

npm install --save lambda-formation-route53-hostedzone
kmcgrath commented 7 years ago

This is more tricky than it appears. The organization of a lambda-formation project is important, including the paths. The design is so that as little code is loaded (required) as possible before executing the action code.

When a request comes in at the top index.js of a lambda-formation project nothing about the rest of the project has been loaded. The corresponding lib/resources directory is checked and from there the action and only that action and its requirements are loaded. This keeps overhead code to the minimum needed to run a specific action.

Furthermore, every level, project, resource and action are all lambda functions themselves. You can set a Lambda handler to be the project index.js, the resource index.js or a direct create.js, update.js or delete.js action and it will "just work". This allows you to use any script as a handler with or without CloudFormation.

This follows exactly how Lambda itself loads handlers. You can specify a path to any .js file in the project. This project partly acts as a really dumb (but hopefully fast) router, that makes it all compatible with CloudFormation.

A thought could be to add a config file that maps a resource name to a module. Then paths could still be followed through that node_modules directory. That would however break the compatibility with Lambda handler paths.

We use multiple lambda-formation projects. We keep them small, many times a single resource. That way they can be versioned and released more like microservices.

I'm open to suggestions. Did you have concerns about making multiple projects? Need for one project?

You can also require any modules you want in the actions themselves. If you were to do an npm install of another lambda-formation project you could hook it up by creating the corresponding actions with a single require.

> npm install lf-other-project

myproject/lib/resources/otherProjectResource/create.js

require("lf-other-project/lib/resources/res1/create");

Then the Lambda handler path compatibility would still work. A yeoman generator could be used to do this "automagically."

Open to discussion, thanks for the submission.

estahn commented 7 years ago

@kmcgrath Thanks for your thorough response.

I wouldn't want to share the entire project in an npm package, but only a single resource, e.g.

├── create.js
├── delete.js
└── update.js

As for the performance penalty, it should be pretty much the same as loading files. module_exist could be used to check if lambda-formation-<resource name> exist. The code is fairly simple and could even be copied into lambda-formation itself.

Furthermore, every level, project, resource and action are all lambda functions themselves.

If you don't need this requirement the action files could probably be simplified further to:

module.exports.handler = function (event, context) {
    < code >
};

Removing handler.apply(this, [event, context, create]);. Since the action is implied by the file anyways (convention over configuration).

Also index.js in every resource directory seems to be unnecessary. Also the entry point index.js could be simplified to something like module.exports.handler = require('lambda-formation').project.handler;.

This all depends on above requirement of course. I feel the requirement is unnecessary since you're using a framework.

Thoughts?

kmcgrath commented 7 years ago

Just wanted to leave a message that I have not forgotten about this. Just have not had a chance to cycle back this week. Will update soon.

estahn commented 7 years ago

Some good features that could be incorporated into lambda-formation: https://github.com/andrew-templeton/cfn-lambda