Migration Guide: Serverless + Bref + Laravel

Thiago Marini
No Deploys On Friday
4 min readDec 21, 2018

Attention, this article is outdated! Bref has launched version 0.3 that supports Lambda layers, so there’s no need to use version 0.2 anymore. However most of Laravel issues listed in here are still valid and it’s worth going through them.

Quick migration guide for the poor souls who like me are migrating Laravel apps to serverless. This is a summary of challenges I’ve met when adapting dozens of Laravel apps and APIs to run on AWS Lambda.

Problem

We at Weengs are spending too much money running all of our environments on Elastic Beanstalk. Apart from being an already old AWS technology, nowadays it makes no sense provisioning and paying for servers you don’t fully use. Also needless to say that monitoring and maintaining servers is boring and diverts focus from development.

Solution

Migrate our staging environment to serverless to give it a go and try to fail fast. If it’s a good fit for us and fulfils our expectations we’ll migrate the rest of our environments, including production. We also considered containerised solutions but ended up choosing serverless because it reduces devops workload.

Technologies chosen:

Good news

PHP sweet revenge. The historically criticised request scope of PHP fits like a glove on Lambda invocation mechanism. No shift in mindset required for us PHP devs ❤.

You’ll dramatically reduce your AWS bills if you don’t have a high volume system.

Stateless REST APIs are easier to migrate than apps with HTML views.

Bad news

Making changes in your architecture is never simple, so be ready for some bruises.

  • Patchy solution. Running PHP on Lambda is a bit patchy, the application is passed as an argument and executed by a PHP binary file. We’ ll have to wait a bit more for better solutions.
  • You’ll lose your local filesystem. The only writable folder on Lambda is tmp/, so everything needs to happen there, also it usually gets destroyed at the end of the function execution. So if you use the local filesystem for session, caching, file upload or anything else you’ll need to do some changes. In our case we already used S3 for file upload, the only change we did was to move session and caching to the database (as a quick win), in the future we’ll use ElasticCache for them. Luckily Laravel has very good abstractions for these operations and changing their drivers is a breeze.
  • Timeouts. We’re keeping Bref’s suggestion of 20 seconds timeout (the default is 6 seconds). So if you’re performing long running operations you’ll definitely have problems. Thankfully for us 20 seconds is an eternity, so far so good.
  • Cold-starts. It’s a thing, your architecture will either need to tolerate cold-starts or you’ll have to create some warm-up scripts to avoid it.

Pain points

During the migration I bumped into some tricky issues. The the most painful were:

Loss of the public folder: if you keep app specific assets in the public folder you’ll have problems as that folder is ignored by Bref — the entry point to the application is the bref.php file, not Laravel’s public/index.php. I tried out some sorcery with routes + reading and outputing file contents but gave up quickly, ended up using S3 for it, which in turn caused some changes on the pipeline build script as the public folder now needs to be uploaded to S3 (respecting branch names) before deployments.

Indiscriminate use of env() outside of config files: For some reason we started calling Laravel’s env() global function outside of config files. The problem is that Bref calls php artisan config:cache during the build and any calls to env() returns false after the cache is built. The solution was to refactor the apps to use config() instead of env() (which is the right thing to do).

SQS queues: This was a big one.

First you need to wire Lambda with SQS, which is easy. Just add an extra event to the handler and it will start listening to SQS events:

serverless.yml file changes:

events:
- http: 'ANY /'
- http: 'ANY {proxy+}'
- sqs: SQS-QUEUE-ARN

And don’t forget to give the Lambda permission to interact with SQS:

iamRoleStatements:
- Effect: "Allow"
Action:
- "sqs:SendMessage"
- "sqs:ReceiveMessage"
Resource: SQS-QUEUE-ARN

Now the real problem: Bref’s Laravel’s adaptor doesn’t understand SQS events, you’ll have to fire Laravel jobs manually.

In the bref.php file you’ll notice there’s only one handle, the HTTP one. So you’ll need to add a “simple handler” to catch the event, like this one (very hacky):

And that’s it folks, if you survive Bref’s Laravel instructions and mine you’ll have your Laravel app up and running on Lambda. Hope this article was good help :)

--

--