Installation
composer require dayspring-tech/lambda-bundle
Dockerfile Integration
Add this to your Dockerfile (place it after composer install):
COPY vendor/dayspring-tech/lambda-bundle/Bootstrap/service.php /var/runtime/bootstrap
RUN chmod +x /var/runtime/bootstrap
First Lambda Handler
Create a service implementing LambdaHandlerServiceInterface:
// src/Service/MyLambdaHandler.php
namespace App\Service;
use DayspringTech\LambdaBundle\LambdaHandlerServiceInterface;
class MyLambdaHandler implements LambdaHandlerServiceInterface
{
public function handle(array $event): array
{
return ['status' => 'success', 'data' => ['message' => 'Hello from Lambda!']];
}
}
Register the Handler
Tag it as a public service in config/services.yaml:
services:
App\Service\MyLambdaHandler:
tags: ['lambda.handler']
Deploy Build your Docker image and push to AWS ECR. Deploy via AWS Lambda with:
provided.al2 (or equivalent)/var/runtime/bootstrapindex.php (default entrypoint in the bundle)Event Handling
The bundle automatically parses AWS Lambda events (e.g., APIGatewayProxyRequest). Access them via:
public function handle(array $event): array
{
$request = $event['requestContext']['http'] ?? null;
return ['body' => json_encode(['input' => $request['path']])];
}
Kernel Bootstrapping The Symfony kernel boots once per Lambda invocation (unlike Bref’s console-only approach). Leverage full Symfony features:
public function handle(array $event)
{
$entityManager = $this->container->get('doctrine')->getManager();
// Use Doctrine, services, etc.
}
Dependency Injection Inject services directly into your handler:
use Symfony\Component\HttpFoundation\RequestStack;
class MyLambdaHandler implements LambdaHandlerServiceInterface
{
public function __construct(private RequestStack $requestStack) {}
public function handle(array $event): array
{
$request = $this->requestStack->getCurrentRequest();
// ...
}
}
Environment Awareness
Use APP_ENV and APP_DEBUG via Symfony’s ParameterBagInterface:
public function __construct(private ParameterBagInterface $params) {}
public function handle(array $event): array
{
if ($this->params->get('kernel.debug')) {
return ['debug' => true];
}
return ['debug' => false];
}
Error Handling Throw exceptions to return HTTP 500 responses:
public function handle(array $event): array
{
if ($event['error']) {
throw new \RuntimeException('Custom error message');
}
return [];
}
API Gateway Proxy Integration
Use $event['body'] to access raw JSON payloads:
$data = json_decode($event['body'], true);
S3 Event Triggers Parse S3 events:
$bucket = $event['Records'][0]['s3']['bucket']['name'];
$key = $event['Records'][0]['s3']['object']['key'];
DynamoDB Streams Access DynamoDB records:
$dynamoEvent = $event['Records'][0]['dynamodb'];
$newImage = $dynamoEvent['NewImage'];
Custom Runtime API
Extend the runtime API by overriding Bootstrap/service.php:
// Add custom initialization logic before kernel boot
require __DIR__.'/../vendor/autoload.php';
$customConfig = new CustomConfig();
$kernel = new AppKernel('prod', $customConfig);
Cold Starts
Memory Limits
OutOfMemoryException for large payloads.memory_get_usage() and adjust Lambda memory settings.Circular Dependencies
autowire: false and explicit constructor injection:
services:
App\Service\MyLambdaHandler:
autowire: false
public: true
Event Parsing Quirks
APIGatewayProxyRequest vs. raw JSON).if (!isset($event['body'])) {
throw new \InvalidArgumentException('Missing event body');
}
Logging
monolog may not log to CloudWatch by default.monolog handler in config/packages/monolog.yaml:
handlers:
main:
type: stream
path: php://stdout
level: debug
channels: ["!event"]
Local Testing
Use the bref CLI to test locally:
composer require --dev bref/bref
vendor/bin/bref run src/Service/MyLambdaHandler::handle
X-Ray Tracing Enable AWS X-Ray for distributed tracing:
// In your handler
$this->container->get('aws.xray')->beginSegment('LambdaHandler');
try {
// Handle logic
} finally {
$this->container->get('aws.xray')->endSegment();
}
Environment Variables
Access Lambda environment variables via Symfony’s ParameterBag:
$this->params->get('MY_CUSTOM_VAR');
Timeout Handling
set_time_limit() if needed:
set_time_limit(900); // 15 minutes
Custom Runtime Initialization
Override Bootstrap/service.php to add pre-boot logic:
// Example: Load custom environment variables
putenv('CUSTOM_VAR=value');
require __DIR__.'/../vendor/autoload.php';
Handler Middleware Create a middleware stack for handlers:
use DayspringTech\LambdaBundle\Middleware\LambdaMiddlewareInterface;
class LoggingMiddleware implements LambdaMiddlewareInterface
{
public function handle(array $event, callable $next): array
{
error_log('Event received: '.json_encode($event));
return $next($event);
}
}
Register via tag:
services:
App\Middleware\LoggingMiddleware:
tags: ['lambda.middleware']
Kernel Events Dispatch Symfony events during Lambda execution:
$this->container->get('event_dispatcher')->dispatch(
new LambdaEvent($event),
'lambda.handle'
);
Custom Response Formats
Extend the response format by overriding the bundle’s ResponseFactory:
use DayspringTech\LambdaBundle\Response\ResponseFactoryInterface;
class CustomResponseFactory implements ResponseFactoryInterface
{
public function create(array $data, int $status = 200): array
{
return [
'statusCode' => $status,
'body' => json_encode($data),
'headers' => ['Content-Type' => 'application/json'],
'customField' => 'value' // Extend response
];
}
}
Bind it in config/services.yaml:
services:
DayspringTech\LambdaBundle\Response\ResponseFactoryInterface: '@App\Response\CustomResponseFactory'
How can I help you explore Laravel packages today?