Hopefully in choosing to read this article you will have read my first article about compiling RoadRunner from source and now you want to continue into making customisations to the resulting server with your very first plugin. If you haven’t read it then you might be best doing so before continuing as it establishes steps you’ll need to take in this article.
For the sake of simplicity you should also have a GitHub account as we’ll be using a template repository to make a copy and store in your own repository on GitHub. You could also just download the code but doing so would require additional steps that won’t be covered here.
If you have any difficulties or just want to play with the code you can find them all in the following repos:
Making a plugin for RoadRunner is fairly simple but is a bit of a steep learning curving if you’re also still new to Golang. Writing the plugin is one thing but making a tested plugin that meets the standard of other Go devs is difficult. To speed up this process I’ve produced a template project on GitHub that you can copy to get yourself started.
The basics of a plugin is a simple structure in Go that implements the interfaces required to be a service in Endure. Endure is a service container for Golang, written by Spiral, the same company that develops _RoadRunne_r.
The template project also sets out tests and CI via GitHub Actions. This will be a great starting point for making your own plugin. Once you’ve copied the project we can get started.
The first step in customising the Plugin is to setup the go.mod file. When copying the template directory you will have created it with a new name which is unique on github. So for instance if your username is foo and you name the repository bar you will have a unique repository at github.com/foo/bar. Modules in go are equally named based on where the module can be found so the go get command knows where to download the source code from. The go.mod file has a module directive, this must reflect it’s location online otherwise it won’t be accepted by the go get command. You can see below what the file looks like and what needs to be changed.
module github.com/_<your account>_/_<repository name>_ go 1.16 require ( github.com/spiral/endure v1.0.2 github.com/spiral/errors v1.0.11 github.com/spiral/goridge/v3 v3.1.4 github.com/spiral/roadrunner/v2 v2.3.2 github.com/stretchr/testify v1.7.0 )
The next step is to come up with a name for the plugin itself. This name will be used in the container as a unique identifier but also will show up in the logs when a plugin makes use of the logging service. This makes it easy to know if your plugin is working.
We make this change in the plugin.go file by changing the PluginName constant.
const PluginName = "name_of_your_plugin"
After doing so we have a basic enough plugin ready to be compiled into our custom RoadRunner build.
By this point you hopefully have cloned/forked a copy of the RoadRunner binary project. If not, you need to do so.
Installing a plugin into RoadRunner requires only a couple steps. First we have to download the dependency from within a terminal, where the current directory is the route for our RoadRunner binary project. Making sure the module name is the same as the account/repository our go.mod file which only need to tell go to add the module to the binary project to keep it as a dependency. This is really no different than the way PHP uses composer to manage dependencies.
We can do this by simply running the following command:
go get github.com/<your account>/<repository name>
Take note the package url should be the same as the module name in go.mod or this will cause the package installation to fail. So for me that would be go get github.com/peterfox/roadrunner-plugin-demo.
Now in the binary project we must edit the internal/container/plugins.go file. Here we can import the plugin and add it to the list of other plugins like so:
After this we can compile the binary as we have done so before and if there are no issues we can go about using it with Laravel by simply copying the compiled rr binary to our Laravel project that has Octane already installed.
We now only need to add our plugin to the .rr.yaml config to make sure that the plugin loads:
name_of_your_plugin: value: foobar
After this we can start up the Octane with the php artisan octane:start command. At this point if we have done everything correctly we will have no errors in executing the command and can still load the default route on our Laravel application as we could before.
Once you have a plugin with methods exposed via RPC, you now want to use them in Laravel itself. This will equally require you to install an extra PHP package to communicate with the RPC server. This will be done with Composer:
composer require spiral/goridge
Then we can implement a very simple route to demonstrate calling the RPC server.
Once we test this route through we should get back a simple message as a response:
This response means that the PHP code has managed to serialise a PHP array, deserialise in the RoadRunner application and then return the same structure to be serialized and deserialized from Go to PHP creating a bridge between the two programming languages.
What we’ve done here may not seem much but it really is the start of something very powerful. Under the hood we’ve managed to expose the power of Go to our PHP application, something that would be far more complicated if we were writing a PHP extension instead.
RPC accessibility isn’t the only functionality that RoadRunner plugins can offer and I hope to be exploring more of this in the future in further articles as well as little tips for developing with Golang and diving a little into the components RoadRunner uses.
I’m Peter Fox, a software developer in the UK who works with Laravel among other things. Thank you for reading my article, I’ve got several more on both medium and dev.to. If you want to know more about me, head over to https://www.peterfox.me. Also feel free to follow me @SlyFireFox on twitter for more Laravel tips and tutorials in the future.