├── .artillery
└── profile.yaml
├── .roadrunner
├── .rr.yaml
└── worker.php
├── README.md
├── composer.json
└── src
├── Application
├── ApplicationInterface.php
├── MagentoAppWrapper.php
├── Request
│ ├── Registry.php
│ └── RegistryInterface.php
└── Response
│ ├── ResponseConverter.php
│ └── ResponseConverterInterface.php
├── Framework
├── App
│ └── Request
│ │ └── Http.php
├── RequestTrait.php
└── Webapi
│ ├── Request.php
│ └── Rest
│ └── Request.php
├── Plugin
├── App
│ └── State
│ │ └── MuteAreaException.php
└── Webapi
│ └── Controller
│ └── Rest
│ └── InputParamsResolver
│ └── RemoveRouteState.php
├── etc
├── di.xml
└── module.xml
└── registration.php
/.artillery/profile.yaml:
--------------------------------------------------------------------------------
1 | config:
2 | environments:
3 | apache:
4 | target: "http://rr.local"
5 | roadrunner:
6 | target: "http://0.0.0.0:8086"
7 | defaults:
8 | headers:
9 | Authorization: "Bearer ee5n7bh0ru4se3rhqo5hshy0yfapznpq"
10 | phases:
11 | - duration: 1
12 | arrivalRate: 1
13 | name: "Main phase"
14 | variables:
15 | prefix:
16 | - "S6-AP-"
17 | scenarios:
18 | - name: "S1. Create category"
19 | flow:
20 | - loop:
21 | - post:
22 | url: "/rest/V1/categories"
23 | json:
24 | category:
25 | name: "name-{{prefix}}-{{ $loopCount }}"
26 | parent_id: 2
27 | is_active: true
28 | count: 100
29 | - name: "S2. Countries list"
30 | flow:
31 | - loop:
32 | - get:
33 | url: "/rest/V1/directory/countries"
34 | count: 100
35 | - name: "S3. Product types list"
36 | flow:
37 | - loop:
38 | - get:
39 | url: "/rest/V1/products/types"
40 | count: 100
41 | - name: "S4. Product attribute sets list"
42 | flow:
43 | - loop:
44 | - get:
45 | url: "/rest/V1/products/attribute-sets/sets/list?searchCriteria"
46 | count: 100
47 | - name: "S5. Category get"
48 | flow:
49 | - loop:
50 | - get:
51 | url: "/rest/V1/categories/2"
52 | count: 100
53 | - name: "S6. Create product"
54 | flow:
55 | - loop:
56 | - post:
57 | url: '/rest/V1/products'
58 | json:
59 | product:
60 | sku: "sku-{{prefix}}-{{ $loopCount }}"
61 | name: "name-{{prefix}}-{{ $loopCount }}"
62 | attribute_set_id: 4
63 | price: 100
64 | type_id: "simple"
65 | count: 100
66 | - name: "S7. Get product list"
67 | flow:
68 | - loop:
69 | - get:
70 | url: "/rest/V1/products?searchCriteria[pageSize]=20"
71 | count: 100
72 |
73 |
--------------------------------------------------------------------------------
/.roadrunner/.rr.yaml:
--------------------------------------------------------------------------------
1 | http:
2 | address: 0.0.0.0:8086
3 | workers:
4 | command: "php worker.php"
5 | pool:
6 | numWorkers: 1
7 |
--------------------------------------------------------------------------------
/.roadrunner/worker.php:
--------------------------------------------------------------------------------
1 | createApplication(\Magento\Framework\App\Http::class);
19 |
20 | /** @var ApplicationInterface $psr7Application */
21 | $psr7Application = $bootstrap->getObjectManager()->create(
22 | \Isxam\M2RoadRunner\Application\MagentoAppWrapper::class,
23 | [
24 | 'magentoApp' => $app
25 | ]
26 | );
27 |
28 | while ($request = $psr7->acceptRequest()) {
29 | try {
30 | $response = $psr7Application->handle($request);
31 |
32 | $psr7->respond($response);
33 | } catch (\Throwable $e) {
34 | $psr7->getWorker()->error((string)$e);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Magento2 RoadRunner
2 |
3 | ## How to run
4 |
5 | 1. Install composer package .
6 | 2. Enable Magento2 module `Isxam_M2RoadRunner`.
7 | 3. Copy `.roadrunner/worker.php` to Magento2 root.
8 | 3. Copy `.roadrunner/.rr.yaml.php` to Magento2 root.
9 | 4. Download RoadRunner Server binary `./vendor/bin/rr get`.
10 | 5. Run RoadRunner `./rr serve -v -d`.
11 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "isxam/magento2-roadrunner-performance",
3 | "description": "N/A",
4 | "version": "0.1.0",
5 | "require": {
6 | "php": "~7.1.3||~7.2.0",
7 | "magento/framework": "*",
8 | "spiral/roadrunner": "^1.4"
9 | },
10 | "type": "magento2-module",
11 | "license": [],
12 | "autoload": {
13 | "files": [
14 | "src/registration.php"
15 | ],
16 | "psr-4": {
17 | "Isxam\\M2RoadRunner\\": "src/"
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Application/ApplicationInterface.php:
--------------------------------------------------------------------------------
1 | registry = $registry;
43 | $this->magentoApp = $magentoApp;
44 | $this->responseConverter = $responseConverter;
45 | }
46 |
47 | /**
48 | * @inheritdoc
49 | */
50 | public function handle(ServerRequestInterface $request): ResponseInterface
51 | {
52 | $this->registry->setCurrentRequest($request);
53 |
54 | try {
55 | $magentoResponse = $this->magentoApp->launch();
56 |
57 | $response = $this->responseConverter->convert($magentoResponse);
58 | } catch (\Exception $e) {
59 | $response = $this->buildExceptionResponse($e);
60 | }
61 |
62 | return $response;
63 | }
64 |
65 | /**
66 | * Build exception response.
67 | *
68 | * @param \Exception $e
69 | * @return ResponseInterface
70 | */
71 | private function buildExceptionResponse(\Exception $e): ResponseInterface
72 | {
73 | return new Response(
74 | 500,
75 | [],
76 | $e->getMessage()
77 | );
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Application/Request/Registry.php:
--------------------------------------------------------------------------------
1 | currentRequest = $request;
23 | }
24 |
25 | /**
26 | * @inheritdoc
27 | */
28 | public function getCurrentRequest(): ?ServerRequestInterface
29 | {
30 | return $this->currentRequest;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Application/Request/RegistryInterface.php:
--------------------------------------------------------------------------------
1 | getHttpResponseCode(),
26 | $response->getHeaders()->toArray(),
27 | $response->getBody()
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/Response/ResponseConverterInterface.php:
--------------------------------------------------------------------------------
1 | registry = $registry;
50 | parent::__construct(
51 | $cookieReader,
52 | $converter,
53 | $routeConfig,
54 | $pathInfoProcessor,
55 | $objectManager,
56 | $uri,
57 | $directFrontNames,
58 | $pathInfoService
59 | );
60 | }
61 |
62 | /**
63 | * @inheritdoc
64 | */
65 | protected function getRegistry(): RegistryInterface
66 | {
67 | return $this->registry;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Framework/RequestTrait.php:
--------------------------------------------------------------------------------
1 | getRegistry()->getCurrentRequest()) {
22 | return parent::getMethod();
23 | }
24 |
25 | return $this->getRegistry()->getCurrentRequest()->getMethod();
26 | }
27 |
28 | /**
29 | * @inheritdoc
30 | */
31 | public function getRequestUri()
32 | {
33 | if (!$this->getRegistry()->getCurrentRequest()) {
34 | return parent::getRequestUri();
35 | }
36 |
37 | return $this->getRegistry()->getCurrentRequest()->getUri()->getPath();
38 | }
39 |
40 | /**
41 | * @inheritdoc
42 | */
43 | public function getHeaders($name = null, $default = false)
44 | {
45 | if (!$this->getRegistry()->getCurrentRequest()) {
46 | return parent::getHeaders($name, $default);
47 | }
48 |
49 | $request = $this->getRegistry()->getCurrentRequest();
50 |
51 | $headers = new Headers();
52 | $headers->addHeaders($request->getHeaders());
53 |
54 | if ($name === null) {
55 | return $headers;
56 | }
57 |
58 | if($headers->has($name)) {
59 | return $headers->get($name);
60 | }
61 |
62 | return $default;
63 | }
64 |
65 | /**
66 | * @inheritdoc
67 | */
68 | public function getContent()
69 | {
70 | if (!$this->getRegistry()->getCurrentRequest()) {
71 | return parent::getContent();
72 | }
73 |
74 | return (string)$this->getRegistry()->getCurrentRequest()->getBody();
75 | }
76 |
77 | /**
78 | * @inheritdoc
79 | */
80 | public function getQuery($name = null, $default = null)
81 | {
82 | if (!$this->getRegistry()->getCurrentRequest()) {
83 | return parent::getQuery($name, $default);
84 | }
85 |
86 | $request = $this->getRegistry()->getCurrentRequest();
87 |
88 | $queryParams = (new Parameters());
89 | $queryParams->fromArray($request->getQueryParams());
90 |
91 | if ($name === null) {
92 | return $queryParams;
93 | }
94 |
95 | return $queryParams->get($name, $default);
96 | }
97 |
98 | /**
99 | * @inheritdoc
100 | */
101 | public function getPost($name = null, $default = null)
102 | {
103 | if (!$this->getRegistry()->getCurrentRequest()) {
104 | return parent::getPost($name, $default);
105 | }
106 |
107 | $request = $this->getRegistry()->getCurrentRequest();
108 |
109 | $postParams = new Parameters();
110 | $postParams->fromArray($request->getParsedBody() ?: []);
111 |
112 | if ($name === null) {
113 | return $postParams;
114 | }
115 |
116 | return $postParams->get($name, $default);
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/Framework/Webapi/Request.php:
--------------------------------------------------------------------------------
1 | registry = $registry;
52 | $this->areaList = $areaList;
53 | $this->configScope = $configScope;
54 | parent::__construct($cookieReader, $converter, $areaList, $configScope, $uri);
55 | }
56 |
57 | /**
58 | * @inheritdoc
59 | */
60 | protected function getRegistry(): RegistryInterface
61 | {
62 | return $this->registry;
63 | }
64 |
65 | /**
66 | * @inheritdoc
67 | */
68 | public function getPathInfo()
69 | {
70 | $pathInfo = $this->getRequestUri();
71 | /** Remove base url and area from path */
72 | $areaFrontName = $this->areaList->getFrontName($this->configScope->getCurrentScope());
73 | $pathInfo = preg_replace("#.*?/{$areaFrontName}/?#", '/', $pathInfo);
74 | /** Remove GET parameters from path */
75 | $pathInfo = preg_replace('#\?.*#', '', $pathInfo);
76 |
77 | return $pathInfo;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Framework/Webapi/Rest/Request.php:
--------------------------------------------------------------------------------
1 | registry = $registry;
54 | parent::__construct($cookieReader, $converter, $areaList, $configScope, $deserializerFactory, $uri);
55 | $this->areaList = $areaList;
56 | $this->configScope = $configScope;
57 | }
58 |
59 | /**
60 | * @inheritdoc
61 | */
62 | protected function getRegistry(): RegistryInterface
63 | {
64 | return $this->registry;
65 | }
66 |
67 | /**
68 | * @inheritdoc
69 | */
70 | public function getHttpMethod()
71 | {
72 | return $this->getMethod();
73 | }
74 |
75 | /**
76 | * @inheritdoc
77 | */
78 | public function getPathInfo()
79 | {
80 | $pathInfo = $this->getRequestUri();
81 | /** Remove base url and area from path */
82 | $areaFrontName = $this->areaList->getFrontName($this->configScope->getCurrentScope());
83 | $pathInfo = preg_replace("#.*?/{$areaFrontName}/?#", '/', $pathInfo);
84 | /** Remove GET parameters from path */
85 | $pathInfo = preg_replace('#\?.*#', '', $pathInfo);
86 |
87 | return $pathInfo;
88 | }
89 |
90 | /**
91 | * @inheritdoc
92 | */
93 | public function getBodyParams()
94 | {
95 | $content = (string)$this->getContent();
96 |
97 | return $content ? (array)$this->_getDeserializer()->deserialize($content) : [];
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/Plugin/App/State/MuteAreaException.php:
--------------------------------------------------------------------------------
1 | getAreaCode();
22 | } catch (\Exception $e) {
23 | $proceed($code);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Plugin/Webapi/Controller/Rest/InputParamsResolver/RemoveRouteState.php:
--------------------------------------------------------------------------------
1 | router = $router;
34 | $this->request = $request;
35 | }
36 |
37 | /**
38 | * @param InputParamsResolver $subject
39 | * @param \Closure $proceed
40 | * @return Route
41 | * @throws Exception
42 | */
43 | public function aroundGetRoute(InputParamsResolver $subject, \Closure $proceed)
44 | {
45 | return $this->router->match($this->request);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
8 |
10 |
12 |
14 |
15 |
16 |
17 | Isxam\M2RoadRunner\Framework\Webapi\Rest\Request\Proxy
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/registration.php:
--------------------------------------------------------------------------------
1 |