Writing a Plugin
RoadRunner provides the ability to create custom plugins, event listeners, middlewares, etc., that extend its functionality. It uses Endure container to manage dependencies, this approach is similar to the PHP Container implementation with automatic method injection.
To create a custom plugin, you can follow these steps:
Define a struct with a public
Init
method that returns an error value.Implement the
Service
interface in your struct to provide theServe
andStop
methods.Request dependencies using their respective interfaces and inject them using Endure container.
Register your plugin with RoadRunner by creating a custom version of the
main.go
file and building it.
Below you can find more information about the plugin interface, how to define a plugin, and how to access other plugins.
Interface
RoadRunner plugins are implemented using the Service interface, which provides the Serve
and Stop
methods for starting and stopping the plugin. Additionally, plugins can implement other optional interfaces like Named
, Provider
, Weighted
, and Collector
. These interfaces enable plugins to provide dependencies to other plugins, define their weight in the plugin's topology, and collect plugins that implement specific interfaces.
Here is an example:
Plugin definition
To define a custom plugin, create a struct with a public Init
method that returns an error value (you can use roadrunner-server/errors
as the error
package). In this method, you can access other plugins by requesting dependencies.
Disabling plugin
Sometimes, you may want to disable a plugin at runtime based on certain conditions. For example, if there are no configurations for the plugin, or if there is an initialization error, but you still don't want to stop the execution of the server. In such cases, you can return the special type of error called Disabled
, which can be found in the github.com/roadrunner-server/errors
package. This type of error can only be used in the Init
function of the plugin.
Dependencies
You can access other plugins by requesting dependencies in your Init
method. All dependencies should be represented as interfaces, and a plugin implementing this interface should be registered in the RR's container - Endure.
Configuration
In most cases, your services would require a set of configuration values. RoadRunner can automatically populate and validate your configuration structure using the config
plugin via an interface.
YAML configuration sample
Plugin
Configuration
Serving
Create Serve
and Stop
methods in your structure to let RoadRunner start and stop your service. You may also use a context from the Stop
method to let RR force your plugin to stop after a specified timeout in the configuration.
Plugin
The Serve
method is thread-safe. It runs in a separate goroutine managed by the Endure
container. One note is that you should unblock it when calling Stop
on the container. Otherwise, the service will be killed after the timeout (which can be set in Endure).
Collecting dependencies in runtime
RoadRunner provides a way to collect dependencies at runtime via the Collects
interface. This is very useful for middlewares or extending plugins with additional functionality without changing them.
Let's create an HTTP middleware:
Declare a required interface
Implement
Collects
endure interface in the plugin where you want to have these dependencies in the runtime.
Important notes:
dep.Fits
: method used to check all registered plugins that fit the specified interface.func(pp any){}
: is a callback. You can pass an existing method with afunc (_ any)
signature or anonymous as in the example.(*Middleware)(nil)
: is the second argument of thedep.Fits
method which should be an interface you want to find in the registered plugins.
RPC Methods
Extending your plugin with RPC methods does not change the plugin at all. The only thing you have to do is to create a file with RPC methods (let's call it rpc.go
) and add all RPC methods for the plugin without modifying the plugin itself.
Example based on the informer
plugin:
Suppose we have created a file rpc.go
. The next step is to create a structure:
Create a structure: (logger is optional)
Create a method, which you want to expose:
Create a method called
RPC
that accepts nothing and returnsany
:
RPC plugin will automatically find and register your RPC methods under your plugin name. So, for example, to call the Hello
method you might use the following sample:
Tips
More about plugins can be found here: link
Last updated