- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
109 lines
2.8 KiB
PHP
109 lines
2.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\SlidingWindow;
|
|
|
|
use App\Framework\Core\ValueObjects\Duration;
|
|
use App\Framework\Core\ValueObjects\Timestamp;
|
|
use App\Framework\SlidingWindow\Aggregator\SlidingWindowAggregator;
|
|
|
|
/**
|
|
* In-memory sliding window implementation
|
|
*/
|
|
final class InMemorySlidingWindow implements SlidingWindow
|
|
{
|
|
/**
|
|
* @var array<WindowEntry>
|
|
*/
|
|
private array $entries = [];
|
|
|
|
public function __construct(
|
|
private readonly Duration $windowSize,
|
|
private readonly string $identifier,
|
|
private readonly SlidingWindowAggregator $aggregator,
|
|
) {
|
|
}
|
|
|
|
public function record(mixed $value, Timestamp $timestamp): void
|
|
{
|
|
$this->entries[] = new WindowEntry($value, $timestamp);
|
|
$this->cleanup();
|
|
}
|
|
|
|
public function getValues(?Timestamp $now = null): array
|
|
{
|
|
$now ??= Timestamp::now();
|
|
$this->cleanup($now);
|
|
|
|
return array_map(
|
|
fn (WindowEntry $entry) => $entry->value,
|
|
$this->getValidEntries($now)
|
|
);
|
|
}
|
|
|
|
public function getStats(?Timestamp $now = null): SlidingWindowStats
|
|
{
|
|
$now ??= Timestamp::now();
|
|
$this->cleanup($now);
|
|
|
|
$validEntries = $this->getValidEntries($now);
|
|
$windowStart = $now->diff($this->windowSize) > Duration::zero()
|
|
? Timestamp::fromFloat($now->toFloat() - $this->windowSize->toSeconds())
|
|
: $now;
|
|
|
|
$aggregatedData = [];
|
|
if (! empty($validEntries)) {
|
|
$result = $this->aggregator->aggregate(...$validEntries);
|
|
$aggregatedData = method_exists($result, 'toArray') ? $result->toArray() : [$this->aggregator->getIdentifier() => $result];
|
|
}
|
|
|
|
return new SlidingWindowStats(
|
|
totalCount: count($validEntries),
|
|
windowSize: $this->windowSize,
|
|
windowStart: $windowStart,
|
|
windowEnd: $now,
|
|
aggregatedData: $aggregatedData
|
|
);
|
|
}
|
|
|
|
public function clear(): void
|
|
{
|
|
$this->entries = [];
|
|
}
|
|
|
|
public function getWindowSize(): Duration
|
|
{
|
|
return $this->windowSize;
|
|
}
|
|
|
|
public function getIdentifier(): string
|
|
{
|
|
return $this->identifier;
|
|
}
|
|
|
|
/**
|
|
* Get all valid entries within the window
|
|
*
|
|
* @return array<WindowEntry>
|
|
*/
|
|
private function getValidEntries(Timestamp $now): array
|
|
{
|
|
$cutoffTime = Timestamp::fromFloat($now->toFloat() - $this->windowSize->toSeconds());
|
|
|
|
return array_filter(
|
|
$this->entries,
|
|
fn (WindowEntry $entry) => $entry->isWithinWindow($cutoffTime)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Remove entries outside the window
|
|
*/
|
|
private function cleanup(?Timestamp $now = null): void
|
|
{
|
|
$now ??= Timestamp::now();
|
|
$this->entries = $this->getValidEntries($now);
|
|
}
|
|
}
|