hammerstone/sidecar
Sidecar lets Laravel package, deploy, and invoke AWS Lambda functions directly from your app. Define a simple PHP class plus the files to ship, choose any supported runtime (Node, Python, Java, .NET, Ruby, or OS-only), and execute from PHP.
Installation:
composer require hammerstone/sidecar
php artisan sidecar:configure
First Function:
Create a PHP class extending LambdaFunction (e.g., app/Sidecar/ExampleFunction.php):
namespace App\Sidecar;
use Hammerstone\Sidecar\LambdaFunction;
class ExampleFunction extends LambdaFunction
{
public function handler() { return 'handler.handler'; }
public function package() { return ['resources/lambda']; }
}
Handler File:
Add a runtime-specific handler (e.g., resources/lambda/handler.js):
exports.handler = async (event) => {
return { message: 'Hello from Lambda!' };
};
Deploy & Execute:
php artisan sidecar:deploy --activate
// In a route/controller
$result = ExampleFunction::execute(['key' => 'value']);
Image Generation:
canvas or Pillow libraries, then call it from Laravel routes.Function Development:
runtime() method to specify runtime (e.g., Node::V20, Python::V3_12).public function environment() { return ['KEY' => 'value']; }
public function memory() { return 512; } // MB
public function timeout() { return 30; } // seconds
Deployment Strategies:
php artisan sidecar:deploy --only=ExampleFunction
php artisan sidecar:deploy --pre-warm
sidecar.env in .env to avoid conflicts in shared AWS accounts.Execution Patterns:
$result = ExampleFunction::execute(['input' => 'data']);
ExampleFunction::invokeAsync(['input' => 'data']);
public function invoke() { return 's3:bucket-name'; }
Package Management:
public function package() {
return ['src']->exclude('temp');
}
$package = new Package(['src']);
$package->includeString('config.json', json_encode(['key' => 'value']));
$this->app->singleton(ExampleFunction::class);
SidecarTestCase for mocking Lambda responses:
use Hammerstone\Sidecar\Testing\SidecarTestCase;
public function testFunction() {
$this->mockLambda(ExampleFunction::class, ['output' => 'test']);
$result = ExampleFunction::execute([]);
$this->assertEquals('test', $result['output']);
}
php artisan sidecar:deploy --activate --no-interaction
Runtime Mismatches:
public function runtime() { return Node::V14; }
.NET 7, Node 16) will fail silently; update to supported versions.Function Naming:
sidecar:name to customize:
public function name() { return 'custom-name'; }
Package Paths:
/) or DIRECTORY_SEPARATOR:
return ['resources/lambda' . DIRECTORY_SEPARATOR . 'handler.js'];
base_path('resources/lambda')).Cold Starts:
--pre-warm or set reservedConcurrentExecutions:
public function concurrency() { return 1; }
Environment Variables:
public function environment() {
return ['CHECKSUM' => md5(filemtime('config.json'))];
}
Permissions:
lambda:CreateFunction, lambda:UpdateFunction, lambda:InvokeFunction.iam:PassRole for execution role.ses, sqs were removed in v0.3.6).Logs: Check AWS CloudWatch for Lambda logs or use:
$result = ExampleFunction::execute(['debug' => true]);
Errors:
409 Conflict: Function still updating. Wait or use waitUntilFunctionUpdated():
ExampleFunction::waitUntilFunctionUpdated();
429 Throttling: Increase concurrency limits in AWS or retry with exponential backoff.Local Testing:
sidecar:test to simulate Lambda locally (requires Docker):
php artisan sidecar:test ExampleFunction
Custom Handlers:
LambdaFunction::execute() to add pre/post-processing:
public static function execute(array $payload) {
$payload['meta'] = ['timestamp' => now()];
return parent::execute($payload);
}
Package Macros:
Package class for custom file handling:
\Hammerstone\Sidecar\Package::macro('includeAssets', function () {
return $this->include(base_path('public/assets'));
});
Event Listeners:
sidecar.deploying event:
Event::listen('sidecar.deploying', function ($function) {
if ($function instanceof ExampleFunction) {
$function->addEnvironment(['CUSTOM' => 'value']);
}
});
Container Images:
public function image() { return '123456789012.dkr.ecr.us-east-1.amazonaws.com/my-image:latest'; }
public function ephemeralStorage() { return 1024; } // MB
public function concurrency() { return 10; }
$cacheKey = 'lambda:example:' . md5(json_encode($payload));
return Cache::remember($cacheKey, now()->addMinutes(5), function () use ($payload) {
return ExampleFunction::execute($payload);
});
How can I help you explore Laravel packages today?