Sidecar — Deploy and execute AWS Lambda functions from your Laravel application.

Creating Functions

To create a new Sidecar function, you simply create a new PHP class that extends the abstract Hammerstone\Sidecar\LambdaFunction.

You'll be left with two methods that you need to implement, handler and package

1use Hammerstone\Sidecar\LambdaFunction;
2
3class ExampleFunction extends LambdaFunction
4{
5 public function handler()
6 {
7 // TODO: Implement handler() method.
8 }
9
10 public function package()
11 {
12 // TODO: Implement package() method.
13 }
14}

Function Handler

What you define for your handler depends on what runtime you're using.

In general, it's usually follows the format of file.function. For example, when using the Node runtimes, your handler is always filename.named-export.

If you had the following file:

image.js

1exports.handle = async function() {
2 //
3}

Then your handler would be image.handle:

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 return 'image.handle';
6 }
7
8 public function package()
9 {
10 // TODO: Implement package() method.
11 }
12}

If you were deploying a Python function:

example.py

1def handler_name(event, context):
2 return some_value

Then your handler would be changed to example.handler_name

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 return 'example.handler_name';
6 }
7
8 public function package()
9 {
10 // TODO: Implement package() method.
11 }
12}

If your handler file is nested in a subdirectory, you can just prepend the path:

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 return 'resources/js/image.handle';
6 }
7
8 public function package()
9 {
10 // TODO: Implement package() method.
11 }
12}

You can read more below about packaging, but all paths are relative to your application's base_path.

To read more about what the handler should be based on your runtime, see the following pages in the AWS documentation:

Deployment Package

In order for your Lambda to run, you'll need at least one file, that contains your handler. In reality, you'll likely have many dependencies that support your handler. Sidecar will gather all of those files and zip them up so that they can be delivered to Lambda.

Your only job is to define what files should be included, and optionally which ones should be excluded.

In its simplest use, you can just return an array from the package method.

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 return 'image.handle';
6 }
7
8 public function package()
9 {
10 return [
11 'resources/lambda/image.js'
12 ];
13 }
14}

You can include entire directories. You can also exclude files by prepending an exclamation mark !.

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 return 'image.handle';
6 }
7
8 public function package()
9 {
10 return [
11 // Include the whole directory
12 'resources/lambda',
13 // Except this file
14 '!resources/lambda/ignore.js'
15 ];
16 }
17}

The Package Class

If you need a little more fine-grained control over the packaging process, you can use the Package class.

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 return 'image.handle';
6 }
7
8 public function package()
9 {
10 return Package::make()
11 // Change the default base path.
12 ->setBasePath(resource_path())
13 ->include([
14 'lambda'
15 ])
16 ->exclude([
17 'lambda/ignore.js'
18 ]);
19 }
20}

By default, all paths are relative to your application's base_path(). If you'd like to change that, you can use the setBasePath method shown above.

The Package class also has methods for explicitly including and excluding files, should you prefer that method.

To read more about what you can and should include in your package, based on your runtime, see the following pages in Amazon's documentation:

Runtime

Lambda supports multiple languages through the use of runtimes. You can choose any of the following runtimes by returning its corresponding identifier:

  • Node.js 14: nodejs14.x
  • Node.js 12: nodejs12.x
  • Node.js 10: nodejs10.x
  • Python 3.8: python3.8
  • Python 3.7: python3.7
  • Python 3.6: python3.6
  • Python 2.7: python2.7
  • Ruby 2.7: ruby2.7
  • Ruby 2.5: ruby2.5
  • Java 11: java11
  • Java 8: java8
  • Go 1.x: go1.x
  • .NET Core 3.1: dotnetcore3.1
  • .NET Core 2.1: dotnetcore2.1

E.g. to use the Go runtime, you would return go1.x:

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 //
6 }
7
8 public function package()
9 {
10 //
11 }
12
13 public function runtime()
14 {
15 return 'go1.x';
16 }
17}

Read more in the AWS Documentation.

Name

Your function has a name method that determines how Sidecar names your Lambdas. By default it is based on the name of your function class. You are free to change this if you want, but you're unlikely to need to.

Name Prefix

Regardless of what you choose for your function names, Sidecar will prepend the name of your app and the current environment.

Lambda function names must be unique, so adding these variables to your function names prevents collisions between different apps and environments.

Description

The description is totally up to you, you'll likely not need to change it at all. We have provided a descriptive default.

Memory

The only compute-related configuration that AWS allows you to configure for your Lambda is memory. From their documentation:

Lambda allocates CPU power in proportion to the amount of memory configured. Memory is the amount of memory available to your Lambda function at runtime. You can increase or decrease the memory and CPU power allocated to your function using the Memory (MB) setting. To configure the memory for your function, set a value between 128 MB and 10,240 MB in 1-MB increments. At 1,769 MB, a function has the equivalent of one vCPU (one vCPU-second of credits per second).

By default, Sidecar uses the value in your sidecar.php configuration file, which itself defaults to 512mb.

To change the allocated memory of your function, simply return the number in megabytes.

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 //
6 }
7
8 public function package()
9 {
10 //
11 }
12
13 public function memory()
14 {
15 // 2GB of memory
16 return 2048;
17 }
18}

Because this has cost implications, you should consider what makes the most sense for your use case.

Timeout

Every Lambda function must specify a timeout value, at which point AWS will stop execution. There is a hard upper limit of 15 minutes.

By default Sidecar uses the value from you sidecar.php configuration file, which is defaulted to 300 seconds.

You are free to change that per function by returning a value from the timeout method.

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 //
6 }
7
8 public function package()
9 {
10 //
11 }
12
13 public function timeout()
14 {
15 // Only 30 seconds
16 return 30;
17 }
18}

Layers

Some functions require extra code or data beyond what is in your code package. From Amazon's documentation:

A Lambda layer is a .zip file archive that can contain additional code or data. A layer can contain libraries, a custom runtime, data, or configuration files. Layers promote code sharing and separation of responsibilities so that you can iterate faster on writing business logic.

If you want to include layers in your Lambda, you'll need to provide the full ARN for those layers.

In this example below, we're providing the ARN for a layer that has Node Canvas pre-built for the Lambda runtime.

1class ExampleFunction extends LambdaFunction
2{
3 public function handler()
4 {
5 //
6 }
7
8 public function package()
9 {
10 //
11 }
12
13 public function timeout()
14 {
15 return [
16 // Node Canvas from https://github.com/jwerre/node-canvas-lambda
17 'arn:aws:lambda:us-east-2:XXXX:layer:node_canvas:1',
18 ];
19 }
20}

Note that your layers must be in the same AWS region as your Lambdas!

Interacting with Deployment

Sidecar dispatches global events as it's deploying and activating functions. It also calls instance methods on each function, should you care to do anything at that time.

The following four methods are available to you:

  • beforeDeployment
  • afterDeployment
  • beforeActivation
  • afterActivation