In some cases, it can be useful to embed a RoadRunner server inside another GO program. This is often the case in microservice architectures where you may have a mandated GO framework for all the apps. In such cases it might not be possible to run a stock roadrunner instance, and the only choice is to run roadrunner inside the main app framework / program.
Here's an example of how to embed RoadRunner into a Go program with an HTTP handler:
Import RoadRunner library via go get
command into your Go project:
{% code title="main.go" %}
go get -u github.com/roadrunner-server/roadrunner/v2024.2.0/lib
{% endcode %}
{% code title="main.go" %}
func handleRequest(w http.ResponseWriter, request *http.Request) {
// Find a way to pass that to RoadRunner so PHP handles the request
}
{% endcode %}
{% code title="main.go" %}
import (
"github.com/roadrunner-server/roadrunner/v2024/lib"
)
overrides := []string{} // List of configuration overrides
plugins := lib.DefaultPluginsList() // List of RR plugins to enable
rr, err := lib.NewRR(".rr.yaml", overrides, plugins)
{% endcode %}
Here we use the default list of plugins. The same list of plugin you would get if you were to run rr serve
with a
stock roadrunner binary.
You can, however, choose only the plugins you want and add your own private plugins as well:
{% code title="main.go" %}
overrides := []string{
"http.address=127.0.0.1:4444", // example override to set the http address
"http.pool.num_workers=4", // example override of how to set the number of php workers
} // List of configuration overrides
plugins := []interface{}{
&informer.Plugin{},
&resetter.Plugin{},
// ...
&httpPlugin.Plugin{},
// ...
&coolCompany.Plugin{},
}
rr, err := roadrunner.NewRR(".rr.yaml", overrides, plugins)
{% endcode %}
Roadrunner can respond to HTTP requests, but also gRPC ones or many more. Because this is all done via plugins that each listen to different types of requests, ports, etc...
So when we talk about passing a request to roadrunner, we're actually talking about passing the request to roadrunner's HTTP plugin. To do this, we need to keep a handle on the http plugin.
{% code title="main.go" %}
overrides := []string{} // List of configuration overrides
httpPlugin := &httpPlugin.Plugin{},
plugins := []interface{}{
&informer.Plugin{},
&resetter.Plugin{},
// ...
httpPlugin,
// ...
&coolCompany.Plugin{},
}
rr, err := roadrunner.NewRR(".rr.yaml", overrides, plugins)
{% endcode %}
The HTTP plugin is itself an http.Handler
so it's now very easy to use it to let roadrunner and PHP handle the
request:
{% code title="main.go" %}
overrides := []string{
// override the http plugin's address value for the current run of the program
"http.address=127.0.0.1:4444",
} // List of configuration overrides
httpPlugin := &httpPlugin.Plugin{},
plugins := []interface{}{
&informer.Plugin{},
&resetter.Plugin{},
// ...
httpPlugin,
// ...
&coolCompany.Plugin{},
}
rr, err := roadrunner.NewRR(".rr.yaml", overrides, plugins)
if err != nil {
return err
}
func handleRequest(w http.ResponseWriter, request *http.Request) {
return httpPlugin.ServeHTTP(w, request)
}
{% endcode %}
Once everything is ready, we can start the roadrunner instance:
{% code title="main.go" %}
errCh := make(chan error, 1)
go func() {
errCh <- rr.Serve()
}()
{% endcode %}
rr.Serve()
will block until it returns an error or nil
if it was stopped gracefully.
To gracefully stop the server, we simply call rr.Stop()
When you run roadrunner, it goes through multiple phases of initialization, running, stopping etc... Sometimes it is useful to know about those, be it for debugging, to know if you're ready to accept requests, or if you can gracefully shutdown the main program.
You can call rr.CurrentState()
on your roadrunner instance to retrieve one of the following states:
{% code title="main.go" %}
package fsm
// github.com/roadrunner-server/endure/pkg/fsm
type State uint32
const (
Uninitialized State = iota
Initializing
Initialized
Starting
Started
Stopping
Stopped
Error
)
{% endcode %}
Additionally, the actual status name can be obtained via rr.CurrentState().String()
.