Adding a microservice to your monolith

February 17, 2022

I gave a live-coding presentation about this at Laracon. If you'd like to see the whole thing you can watch here, or if you want to skip the ~5 minutes of slides and jump straight to the code, you can start here.

Monoliths are great. We love monoliths! They're easy to develop, deploy, and host. Specifically here I'm talking about monoliths like Rails or Laravel. With each of those frameworks, there are a lot of hosting providers that are specifically tuned for them.

But what happens when you need to step slightly outside of your Rails or Laravel monolith and add a single node process, a bit of Python, deploy headless Chrome, or run a bit of some other language?

Now you have to decide if you're going to take on the devops complexity yourself or reach for "microservices" for a single function.

Adding microservices relieves some of the devops complexity in that you don't have to install, configure, and maintain the language and libraries. While it relieves some of that, it adds coordination complexity. You now have two separate repos, two separate deploy processes, and you have to figure out how to talk to (and secure!) your new microservice.

There is a nice middle ground though.

Microservices in Your Monolith

Instead of creating a separate repo and deployment process for your application, you can keep your "microservice" inside of your monolith, using a package like Sidecar.

Sidecar is only available for Laravel at the moment.

Sidecar packages, deploys, and executes serverless functions from your Laravel application. The current stable version supports AWS Lambda, but I'll be expanding to Vercel in the next few weeks.

Creating a Lambda function is as easy as creating a PHP class:

App\Sidecar\ExampleFunction.php

namespace App\Sidecar;
 
use Hammerstone\Sidecar\LambdaFunction;
 
class ExampleFunction extends LambdaFunction
{
public function handler()
{
return 'sidecar/example@hello';
}
 
public function package()
{
return [
'sidecar/example.js'
];
}
}
Code highlighting powered by torchlight.dev (A service I created!)

And a handler class:

sidecar/example.js

exports.hello = async function (event) {
return `Hello World`
}

Sidecar will package up all the files and deploy it to Lambda. Now you can execute the function on Lambda from your Laravel application:

return ExampleFunction::execute()->body();

That calls the function on Lambda and returns the result to your Laravel application. It does this through the AWS SDK so that you don't have to set up API Gateway and worry about securing any endpoints or futzing about with DNS.

Deploying to Lambda is now as easy as adding a command to your deploy script:

php artisan sidecar:deploy

Going further, you can deploy anything that Lambda supports! If you want to run a Python function, you can:

App\Sidecar\ExampleFunction.php

namespace App\Sidecar;
 
use Hammerstone\Sidecar\LambdaFunction;
use Hammerstone\Sidecar\Runtime;
 
class ExampleFunction extends LambdaFunction
{
public function handler()
{
return 'sidecar/example@hello';
}
 
public function runtime()
{
// Set the runtime to Python
return Runtime::PYTHON_39;
}
 
public function package()
{
return [
// Change the handler to a python function
'sidecar/example.py'
];
}
}

Now you have a Python function on Lambda, that you can execute from your Laravel application.

Are People Actually Using This?

Yes! I opened an issue on the Sidecar repo a while back to ask how people are using it and got several interesting responses.

Here are some of them:

  • We've created two automations for our product, one managing Zoom dashboard and the other manages another third-party. We have 4 sidecar lambdas running. We're using Node 14, Chromium, puppeteer and Vapor.
  • LibreOffice Lambda for document conversion.
  • Headless Chrome/Puppeteer lambda for PDF/Screenshot/Image to PDF
  • Node running Sharp to do quick texture resizes in parallel
  • Node running Puppeteer to take screengrabs of 3D objects for thumbnails
  • Node running some 3D specific tooling to optimise mesh files
  • Running statistical functions from the SciPy library (Python)
  • Executing statistics code in R (AWS Linux container with a lot of dedicated installed libraries)
  • JS Server Side Rendering
  • Generating Ruby Gems in a Sidecar from PHP

Adding a microservice to your monolith is a viable option when you need to step a little bit outside of your monolith and don't want to spin up a whole microservice architecture. Is it truly a microservice? Who knows. But it is a great way of expanding your application's capabilities without drastically expanding its devops footprint.

You can watch me live code this whole thing and you'll get a little better sense of the excitement behind this method.

As always, please reach out to me on Twitter if you have any ideas about this!

Me

Thanks for reading! My name is Aaron and I write, make videos , and generally try really hard .

If you ever have any questions or want to chat, I'm always on Twitter.

You can find me on YouTube on my personal channel or my behind the scenes channel.

If you love podcasts, I got you covered. You can listen to me on Mostly Technical .