1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
RoadRunner
==========
[![Latest Stable Version](https://poser.pugx.org/spiral/roadrunner/version)](https://packagist.org/packages/spiral/roadrunner)
[![GoDoc](https://godoc.org/github.com/spiral/roadrunner?status.svg)](https://godoc.org/github.com/spiral/roadrunner)
[![Build Status](https://travis-ci.org/spiral/roadrunner.svg?branch=master)](https://travis-ci.org/spiral/roadrunner)
[![Go Report Card](https://goreportcard.com/badge/github.com/spiral/roadrunner)](https://goreportcard.com/report/github.com/spiral/roadrunner)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/spiral/roadrunner/badges/quality-score.png)](https://scrutinizer-ci.com/g/spiral/roadrunner/?branch=master)
[![Codecov](https://codecov.io/gh/spiral/roadrunner/branch/master/graph/badge.svg)](https://codecov.io/gh/spiral/roadrunner/)
High-Performance PSR-7 PHP application server, load balancer and process manager.
Features:
--------
- PSR-7 HTTP server (file uploads, error handling, static files, hot reload, middlewares, event listeners)
- extendable service model (plus PHP compatible RPC server)
- no external services, drop-in (based on [Goridge](https://github.com/spiral/goridge))
- load balancer, process manager and task pipeline
- frontend agnostic (queue, REST, PSR-7, async php, etc)
- works over TCP, unix sockets and standard pipes
- automatic worker replacement and safe PHP process destruction
- worker lifecycle management (create/allocate/destroy timeouts)
- payload context and body
- control over max jobs per worker
- protocol, worker and job level error management (including PHP errors)
- memory leak failswitch
- very fast (~250k rpc calls per second on Ryzen 1700X over 16 threads)
- works on Windows
Installation:
--------
```
$ go get github.com/spiral/roadrunner
$ composer require spiral/roadrunner
```
Usage:
------
```
$ cd cmd
$ cd rr
$ go build && go install
$ cp .rr.yaml path/to/the/project
```
> TODO: To be updated with build scripts!
```
$ rr serve -v
```
Example [worker](https://github.com/spiral/roadrunner/blob/master/php-src/tests/http/client.php).
Example config:
---------------
```yaml
# rpc bus allows php application and external clients to talk to rr services.
rpc:
# enable rpc server
enable: true
# rpc connection DSN. Supported TCP and Unix sockets.
listen: tcp://127.0.0.1:6001
# http service configuration.
http:
# set to false to disable http server.
enable: true
# http host to listen.
address: 0.0.0.0:8080
# max POST request size, including file uploads in MB.
maxRequest: 200
# file upload configuration.
uploads:
# list of file extensions which are forbidden for uploading.
forbid: [".php", ".exe", ".bat"]
# http worker pool configuration.
workers:
# php worker command.
command: "php psr-worker.php pipes"
# connection method (pipes, tcp://:9000, unix://socket.unix).
relay: "pipes"
# worker pool configuration.
pool:
# number of workers to be serving.
numWorkers: 4
# maximum jobs per worker, 0 - unlimited.
maxJobs: 0
# for how long pool should attempt to allocate free worker (request timeout). In nanoseconds for now :(
allocateTimeout: 600000000
# amount of time given to worker to gracefully destruct itself. In nanoseconds for now :(
destroyTimeout: 600000000
# static file serving.
static:
# serve http static files
enable: false
# root directory for static file (http would not serve .php and .htaccess files).
dir: "public"
# list of extensions to forbid for serving.
forbid: [".php", ".htaccess"]
```
Examples:
--------
```go
p, err := rr.NewPool(
func() *exec.Cmd { return exec.Command("php", "worker.php", "pipes") },
rr.NewPipeFactory(),
rr.Config{
NumWorkers: uint64(runtime.NumCPU()),
AllocateTimeout: time.Second,
DestroyTimeout: time.Second,
},
)
defer p.Destroy()
rsp, err := p.Exec(&rr.Payload{Body: []byte("hello")})
```
```php
<?php
/**
* @var Goridge\RelayInterface $relay
*/
use Spiral\Goridge;
use Spiral\RoadRunner;
$rr = new RoadRunner\Worker($relay);
while ($body = $rr->receive($context)) {
try {
$rr->send((string)$body, (string)$context);
} catch (\Throwable $e) {
$rr->error((string)$e);
}
}
```
> Check how to init relay [here](./php-src/tests/client.php). More examples can be found in tests.
Testing:
--------
```
$ make test
```
License:
--------
The MIT License (MIT). Please see [`LICENSE`](./LICENSE) for more information.
|