Skip to content

WinterYukky/aws-lambda-custom-runtime-kit

Repository files navigation

AWS Lambda Custom Runtime kit

A kit to easily create AWS Lambda custom runtime in go!

test status MIT license

⚠️ Do you really need this?

If you need a simple custom runtime, please see the documentation for Lambda container images.

Don't? Then let's create a crazy runtime with me!

Install

go get github.com/WinterYukky/aws-lambda-custom-runtime-kit

Get Started

Create struct that implemented AWSLambdaRuntime, and call NewAWSLambdaCustomRuntime(runtime).Invoke().

type AWSLambdaRuntime interface {
	Setup(env *AWSLambdaRuntimeEnvironemnt) error
	Invoke(event []byte, context *Context) (interface{}, error)
	Cleanup(env *AWSLambdaRuntimeEnvironemnt)
}

When result type of Invoke() is string, then string is output as is. Else marshal to json string.

Architecture

AWS Lambda Custom Runtime kit abstracts the AWS Lambda runtime API and simplifies the creation of custom runtimes by writing only the necessary parts.

Next, the architecture of the AWS Lambda Custom Runtime kit is represented in the sequence diagram.

sequenceDiagram
    autonumber
    participant AWS Lambda
    participant Custom runtime kit
    actor Your runtime
    AWS Lambda->>+Custom runtime kit: Init
    Custom runtime kit->>+Your runtime: Setup()
    Your runtime-->>-Custom runtime kit: error
    opt return error
        Custom runtime kit->>AWS Lambda: Initilize error
    end
    loop
        Custom runtime kit->>+AWS Lambda: Get an event
        AWS Lambda-->>-Custom runtime kit: event
        Custom runtime kit->>+Your runtime: Invoke()
        Your runtime->>+Any: any logic
        Any-->>-Your runtime: result
        Your runtime-->>-Custom runtime kit: result, error
        opt return error
            Custom runtime kit->>AWS Lambda: Invoke error
        end
        Custom runtime kit->>+AWS Lambda: send result
    end
    Custom runtime kit->>Your runtime: Cleanup()
    Custom runtime kit-->>-AWS Lambda: Shutdown
Loading

Example of shell runtime

main.go

package main

import (
	"fmt"
	"log"
	"os/exec"

	crkit "github.com/WinterYukky/aws-lambda-custom-runtime-kit"
)

func main() {
	bashRuntime := BashRuntime{}
	customRuntime := crkit.NewAWSLambdaCustomRuntime(bashRuntime)
	if err := customRuntime.Invoke(); err != nil {
		log.Fatalf("Failed to invoke lambda: %v", err)
	}
}

// BashRuntime is runtime that execute shell script.
type BashRuntime struct {}

// Setup is initialize phase of runtime.
// You can validate the invoked function in this phase.
// If you return error, Custom runtime kit responses initialize error to AWS Lambda and finish invoke.
func (b BashRuntime) Setup(env *crkit.AWSLambdaRuntimeEnvironemnt) error {
	return nil
}

// Invoke is invoke phase of runtime.
// You need implement your runtime's behavior.
// You can return result and error.
// If you return error, Custom runtime kit responses invoke error to AWS Lambda and finish invoke.
// When you return result as string, then custom runtime kit responses string as it is.
// Else marshal to json string.
func (b BashRuntime) Invoke(event []byte, context *crkit.Context) (interface{}, error) {
	source := fmt.Sprintf("%v/%v.sh", context.LambdaTaskRoot, context.Handler)
	output, err := exec.Command("sh", source).Output()
	if err != nil {
		return nil, err
	}
        // do not return []byte, cast to string
	return string(output), nil
}

// Cleanup is shutdown phase of runtime.
func (b BashRuntime) Cleanup(env *crkit.AWSLambdaRuntimeEnvironemnt) {}

Build

$ go build -a -tags netgo -installsuffix netgo --ldflags '-extldflags "-static"' -o bootstrap
$ zip runtime.zip bootstrap

Upload as Lambda layer

You can upload runtime.zip as Lambda layer.

Write your shell script

You can write script and invoke🎉

echo '{"body": "Hello World", "statusCode": 200}'

The script returns this output.

{
    "body": "Hello World",
    "statusCode": 200
}

Example of SQL runtime

Please see the AWS Lambda SQL Runtime repository

This runtime can writen lambda handler by SQL (sqlite3).

SELECT 'Hello World' body, 200 statusCode;

The SQL return this output.

{
    "body": "Hello World",
    "statusCode": 200
}