Files
michaelschiemer/src/Framework/Discovery/Memory/MemoryGuard.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

204 lines
6.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Discovery\Memory;
use App\Framework\Core\ValueObjects\Byte;
/**
* Memory guard for continuous memory monitoring during discovery operations
*
* Provides real-time memory monitoring with automatic emergency handling
* to prevent out-of-memory conditions during long-running operations.
*/
final class MemoryGuard
{
private CircularMemoryBuffer $memoryHistory;
private int $checkCounter = 0;
private bool $emergencyMode = false;
private mixed $emergencyCallback = null;
public function __construct(
private readonly DiscoveryMemoryManager $memoryManager,
?callable $emergencyCallback = null
) {
$this->memoryHistory = new CircularMemoryBuffer(maxSize: 100);
$this->emergencyCallback = $emergencyCallback;
}
/**
* Check memory status and take action if needed
*/
public function check(): GuardResult
{
$this->checkCounter++;
$memoryStatus = $this->memoryManager->getMemoryStatus();
// Track memory history for leak detection using CircularMemoryBuffer
$this->memoryHistory->add($memoryStatus->currentUsage);
$actions = [];
// Handle critical memory situations
if ($memoryStatus->status === MemoryStatus::CRITICAL && ! $this->emergencyMode) {
$this->emergencyMode = true;
$actions[] = GuardAction::EMERGENCY_CLEANUP;
if ($this->emergencyCallback) {
($this->emergencyCallback)();
}
// Perform immediate cleanup
$cleanupResult = $this->memoryManager->performCleanup();
$actions[] = $cleanupResult->wasEffective()
? GuardAction::CLEANUP_SUCCESSFUL
: GuardAction::CLEANUP_FAILED;
}
// Handle warning conditions
if ($memoryStatus->status === MemoryStatus::WARNING) {
$actions[] = GuardAction::WARNING_ISSUED;
// Suggest cleanup if it's time
if ($this->memoryManager->shouldCleanup($this->checkCounter)) {
$actions[] = GuardAction::CLEANUP_SUGGESTED;
}
}
// Check for memory leaks periodically using CircularMemoryBuffer
if ($this->checkCounter % 20 === 0) {
$leakInfo = $this->memoryManager->checkForMemoryLeaks($this->memoryHistory);
if ($leakInfo !== null) {
$actions[] = match ($leakInfo->severity) {
LeakSeverity::CRITICAL => GuardAction::CRITICAL_LEAK_DETECTED,
LeakSeverity::HIGH => GuardAction::HIGH_LEAK_DETECTED,
LeakSeverity::MEDIUM => GuardAction::MEDIUM_LEAK_DETECTED,
LeakSeverity::LOW => GuardAction::LOW_LEAK_DETECTED
};
}
}
// Reset emergency mode if memory is back to normal
if ($this->emergencyMode && $memoryStatus->status === MemoryStatus::NORMAL) {
$this->emergencyMode = false;
$actions[] = GuardAction::EMERGENCY_MODE_RESET;
}
return new GuardResult(
memoryStatus: $memoryStatus,
actions: $actions,
checkNumber: $this->checkCounter,
emergencyMode: $this->emergencyMode
);
}
/**
* Force emergency cleanup
*/
public function forceEmergencyCleanup(): MemoryCleanupResult
{
$this->emergencyMode = true;
if ($this->emergencyCallback) {
($this->emergencyCallback)();
}
return $this->memoryManager->performCleanup();
}
/**
* Get current memory statistics
*/
public function getStatistics(): GuardStatistics
{
$memoryStatus = $this->memoryManager->getMemoryStatus();
$samples = $this->memoryHistory->getSamples();
$historyCount = $this->memoryHistory->getCount();
$averageUsage = $historyCount > 0
? Byte::fromBytes((int) (array_sum(array_map(fn (Byte $byte) => $byte->toBytes(), $samples)) / $historyCount))
: Byte::zero();
$peakUsage = $historyCount > 0
? array_reduce($samples, fn ($max, $current) => $current->greaterThan($max ?? Byte::zero()) ? $current : $max, Byte::zero())
: Byte::zero();
return new GuardStatistics(
totalChecks: $this->checkCounter,
currentStatus: $memoryStatus,
averageUsage: $averageUsage,
peakUsage: $peakUsage,
historySize: $historyCount,
emergencyMode: $this->emergencyMode
);
}
/**
* Reset guard state
*/
public function reset(): void
{
$this->memoryHistory->clear();
$this->checkCounter = 0;
$this->emergencyMode = false;
}
/**
* Check if it's safe to continue processing
*/
public function isSafeToProcess(): bool
{
$memoryStatus = $this->memoryManager->getMemoryStatus();
return $memoryStatus->status !== MemoryStatus::CRITICAL;
}
/**
* Get recommendations for current memory state
* @return string[]
*/
public function getRecommendations(): array
{
$memoryStatus = $this->memoryManager->getMemoryStatus();
$recommendations = [];
switch ($memoryStatus->status) {
case MemoryStatus::CRITICAL:
$recommendations[] = 'Immediate action required: Reduce batch size or stop processing';
$recommendations[] = 'Consider switching to STREAMING memory strategy';
$recommendations[] = 'Force garbage collection and cleanup caches';
break;
case MemoryStatus::WARNING:
$recommendations[] = 'Consider reducing batch size';
$recommendations[] = 'Enable more frequent cleanup cycles';
$recommendations[] = 'Monitor for memory leaks';
break;
case MemoryStatus::NORMAL:
if ($memoryStatus->memoryPressure->toDecimal() > 0.5) {
$recommendations[] = 'Memory usage is moderate - consider optimization';
}
break;
}
// Check for potential leaks using CircularMemoryBuffer
if ($this->memoryHistory->getCount() > 10) {
$leakInfo = $this->memoryManager->checkForMemoryLeaks($this->memoryHistory);
if ($leakInfo !== null) {
$recommendations[] = "Memory leak detected ({$leakInfo->severity->value}): Review object retention";
}
}
return $recommendations;
}
}