Skip to content

Commit f4cd926

Browse files
committed
Introduce RuntimeScenarioExecutor & MetadataEngineConfig
- Add `RuntimeScenarioExecutor` for orchestrating runtime scenarios and benchmarking. - Implement `RuntimeScenarioMatrix` class to build and execute scenario matrices. - Introduce `MetadataEngineConfig` for centralized metadata configuration and cache handling. - Refactor `MetadataEngine` using `MetadataEngineConfig` and `MetadataTagValueResolver`. - Update tests to include new classes and functionalities.
1 parent b3ec4f5 commit f4cd926

8 files changed

Lines changed: 579 additions & 184 deletions

File tree

src/base/benchmark/RuntimeMatrixRunner.php

Lines changed: 42 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class RuntimeMatrixRunner
2525
private int $requestTimeout;
2626
private ?RuntimeMatrixEnvironment $environment = null;
2727
private ?RuntimeMatrixReportWriter $reportWriter = null;
28+
private ?RuntimeScenarioMatrix $scenarioMatrix = null;
2829

2930
public function __construct(
3031
string $projectRoot,
@@ -67,41 +68,7 @@ public function run(): array
6768
if (count($scenarios) !== 16) {
6869
throw new RuntimeException('Invalid scenario matrix size: expected 16');
6970
}
70-
71-
$scenarioResults = [];
72-
foreach ($scenarios as $scenario) {
73-
$runtime = (string)$scenario['runtime'];
74-
$service = $this->runtimeMap[$runtime]['service'];
75-
$baseUrl = $this->runtimeMap[$runtime]['base_url'];
76-
$scenarioId = $this->scenarioId($scenario);
77-
78-
$this->applyConfigScenario($scenario);
79-
$this->recreateRuntimeService($service, (bool)$scenario['opcache']);
80-
$this->waitForHealth($baseUrl . '/_bench/ping', $this->healthTimeout);
81-
$this->warmup($baseUrl . '/_bench/metadata', min(20, $this->profiles[1]['concurrency'] ?? 20), $this->warmupRequests);
82-
83-
$profileResults = [];
84-
foreach ($this->profiles as $profile) {
85-
$profileResults[] = $this->runLoadProfile(
86-
$baseUrl . '/_bench/metadata',
87-
(string)$profile['name'],
88-
$scenarioId,
89-
(int)$profile['concurrency'],
90-
(int)$profile['requests']
91-
);
92-
}
93-
94-
$stats = [
95-
'runtime' => $this->collectContainerStats($service),
96-
'redis' => $this->collectContainerStats('redis'),
97-
];
98-
99-
$scenarioResults[] = [
100-
'scenario' => $scenario,
101-
'profiles' => $profileResults,
102-
'container_stats' => $stats,
103-
];
104-
}
71+
$scenarioResults = $this->scenarioExecutor()->execute($scenarios);
10572

10673
$this->assertScenarioCompleteness($scenarioResults);
10774
$this->assertNoHttpErrors($scenarioResults);
@@ -126,22 +93,7 @@ public function run(): array
12693
*/
12794
public function buildScenarios(): array
12895
{
129-
$scenarios = [];
130-
foreach (array_keys($this->runtimeMap) as $runtime) {
131-
foreach ([false, true] as $debug) {
132-
foreach ([false, true] as $opcache) {
133-
foreach ([false, true] as $redis) {
134-
$scenarios[] = [
135-
'runtime' => $runtime,
136-
'debug' => $debug,
137-
'opcache' => $opcache,
138-
'redis' => $redis,
139-
];
140-
}
141-
}
142-
}
143-
}
144-
return $scenarios;
96+
return $this->scenarioMatrix()->build($this->runtimeMap);
14597
}
14698

14799
/**
@@ -363,6 +315,45 @@ private function reportWriter(): RuntimeMatrixReportWriter
363315
return $this->reportWriter;
364316
}
365317

318+
private function scenarioMatrix(): RuntimeScenarioMatrix
319+
{
320+
if (!$this->scenarioMatrix instanceof RuntimeScenarioMatrix) {
321+
$this->scenarioMatrix = new RuntimeScenarioMatrix();
322+
}
323+
return $this->scenarioMatrix;
324+
}
325+
326+
private function scenarioExecutor(): RuntimeScenarioExecutor
327+
{
328+
return new RuntimeScenarioExecutor(
329+
$this->runtimeMap,
330+
$this->profiles,
331+
$this->warmupRequests,
332+
$this->healthTimeout,
333+
function (array $scenario): void {
334+
$this->applyConfigScenario($scenario);
335+
},
336+
function (string $service, bool $opcache): void {
337+
$this->recreateRuntimeService($service, $opcache);
338+
},
339+
function (string $url, int $timeout): void {
340+
$this->waitForHealth($url, $timeout);
341+
},
342+
function (string $url, int $concurrency, int $requests): void {
343+
$this->warmup($url, $concurrency, $requests);
344+
},
345+
fn (
346+
string $url,
347+
string $profile,
348+
string $scenarioId,
349+
int $concurrency,
350+
int $requests
351+
): array => $this->runLoadProfile($url, $profile, $scenarioId, $concurrency, $requests),
352+
fn (string $service): array => $this->collectContainerStats($service),
353+
fn (array $scenario): string => $this->scenarioId($scenario)
354+
);
355+
}
356+
366357
/**
367358
* @return array<string, array{service:string,base_url:string}>
368359
*/
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
namespace PSFS\base\benchmark;
4+
5+
final class RuntimeScenarioExecutor
6+
{
7+
/**
8+
* @param array<string, array{service:string,base_url:string}> $runtimeMap
9+
* @param array<int, array{name:string,concurrency:int,requests:int}> $profiles
10+
* @param callable(array{runtime:string,debug:bool,opcache:bool,redis:bool}):void $applyScenario
11+
* @param callable(string, bool):void $recreateRuntime
12+
* @param callable(string, int):void $waitForHealth
13+
* @param callable(string, int, int):void $warmup
14+
* @param callable(string, string, string, int, int):array<string, mixed> $runProfile
15+
* @param callable(string):array<string, string> $collectStats
16+
* @param callable(array{runtime:string,debug:bool,opcache:bool,redis:bool}):string $scenarioId
17+
*/
18+
public function __construct(
19+
private array $runtimeMap,
20+
private array $profiles,
21+
private int $warmupRequests,
22+
private int $healthTimeout,
23+
private $applyScenario,
24+
private $recreateRuntime,
25+
private $waitForHealth,
26+
private $warmup,
27+
private $runProfile,
28+
private $collectStats,
29+
private $scenarioId
30+
) {
31+
}
32+
33+
/**
34+
* @param array<int, array{runtime:string,debug:bool,opcache:bool,redis:bool}> $scenarios
35+
* @return array<int, array<string, mixed>>
36+
*/
37+
public function execute(array $scenarios): array
38+
{
39+
$results = [];
40+
foreach ($scenarios as $scenario) {
41+
$results[] = $this->executeScenario($scenario);
42+
}
43+
return $results;
44+
}
45+
46+
/**
47+
* @param array{runtime:string,debug:bool,opcache:bool,redis:bool} $scenario
48+
* @return array<string, mixed>
49+
*/
50+
private function executeScenario(array $scenario): array
51+
{
52+
$runtime = (string)$scenario['runtime'];
53+
$service = $this->runtimeMap[$runtime]['service'];
54+
$baseUrl = $this->runtimeMap[$runtime]['base_url'];
55+
$scenarioId = ($this->scenarioId)($scenario);
56+
57+
($this->applyScenario)($scenario);
58+
($this->recreateRuntime)($service, (bool)$scenario['opcache']);
59+
($this->waitForHealth)($baseUrl . '/_bench/ping', $this->healthTimeout);
60+
($this->warmup)($this->metadataUrl($baseUrl), $this->warmupConcurrency(), $this->warmupRequests);
61+
62+
return [
63+
'scenario' => $scenario,
64+
'profiles' => $this->profileResults($baseUrl, $scenarioId),
65+
'container_stats' => [
66+
'runtime' => ($this->collectStats)($service),
67+
'redis' => ($this->collectStats)('redis'),
68+
],
69+
];
70+
}
71+
72+
/**
73+
* @return array<int, array<string, mixed>>
74+
*/
75+
private function profileResults(string $baseUrl, string $scenarioId): array
76+
{
77+
$results = [];
78+
foreach ($this->profiles as $profile) {
79+
$results[] = ($this->runProfile)(
80+
$this->metadataUrl($baseUrl),
81+
(string)$profile['name'],
82+
$scenarioId,
83+
(int)$profile['concurrency'],
84+
(int)$profile['requests']
85+
);
86+
}
87+
return $results;
88+
}
89+
90+
private function warmupConcurrency(): int
91+
{
92+
return min(20, $this->profiles[1]['concurrency'] ?? 20);
93+
}
94+
95+
private function metadataUrl(string $baseUrl): string
96+
{
97+
return $baseUrl . '/_bench/metadata';
98+
}
99+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace PSFS\base\benchmark;
4+
5+
final class RuntimeScenarioMatrix
6+
{
7+
/**
8+
* @param array<string, array{service:string,base_url:string}> $runtimeMap
9+
* @return array<int, array{runtime:string,debug:bool,opcache:bool,redis:bool}>
10+
*/
11+
public function build(array $runtimeMap): array
12+
{
13+
$scenarios = [];
14+
foreach (array_keys($runtimeMap) as $runtime) {
15+
array_push($scenarios, ...$this->runtimeScenarios((string)$runtime));
16+
}
17+
return $scenarios;
18+
}
19+
20+
/**
21+
* @return array<int, array{runtime:string,debug:bool,opcache:bool,redis:bool}>
22+
*/
23+
private function runtimeScenarios(string $runtime): array
24+
{
25+
$scenarios = [];
26+
foreach ([false, true] as $debug) {
27+
foreach ([false, true] as $opcache) {
28+
foreach ([false, true] as $redis) {
29+
$scenarios[] = compact('runtime', 'debug', 'opcache', 'redis');
30+
}
31+
}
32+
}
33+
return $scenarios;
34+
}
35+
}

0 commit comments

Comments
 (0)