Files
michaelschiemer/src/Framework/LiveComponents/MEMORY-MANAGEMENT.md
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

6.2 KiB

LiveComponents Memory Management

Current Architecture ( Already Good)

No Instance Caching

  • ComponentRegistry creates fresh instances on each resolve()
  • No memory leaks from accumulated component instances
  • Components are garbage-collected after request

TTL-Based Rendering Cache

  • ComponentCacheManager caches rendered HTML only
  • Automatic expiry via Cacheable::getCacheTTL()
  • Tag-based invalidation for related components
  • Delegates to Framework Cache (FileCache, ApcuCache, Redis)

Framework Cache Handles Memory

  • FileCache: Disk-based, no memory issues
  • ApcuCache: APCu's memory management
  • Redis: Redis memory eviction policies
  • All support TTL and automatic cleanup

Best Practices

Component Design

DO:

final readonly class UserCardComponent implements LiveComponentContract
{
    public function __construct(
        private ComponentId $id,
        private UserId $userId  // ✅ Small Value Object
    ) {}

    public function getRenderData(): ComponentRenderData
    {
        // ✅ Load data on-demand
        $user = $this->userRepository->find($this->userId);

        return new ComponentRenderData(
            templatePath: 'user-card',
            data: ['user' => $user->toArray()]
        );
    }
}

DON'T:

final readonly class BadComponent implements LiveComponentContract
{
    public function __construct(
        private ComponentId $id,
        private array $allUsers  // ❌ Large dataset in constructor!
    ) {}
}

Caching Strategy

Cache Expensive Renders:

final readonly class StatsComponent implements LiveComponentContract, Cacheable
{
    public function shouldCache(): bool
    {
        return true;  // ✅ Expensive calculation
    }

    public function getCacheTTL(): Duration
    {
        return Duration::fromMinutes(5);  // ✅ Reasonable TTL
    }

    public function getCacheKey(): string
    {
        return "stats:{$this->dateRange->format()}";  // ✅ Vary by parameters
    }
}

Don't Cache Simple Renders:

final readonly class ButtonComponent implements LiveComponentContract
{
    // ❌ Don't implement Cacheable for simple components
    // Caching overhead > render cost
}

Memory Monitoring

Per-Request Component Limits:

// Future Enhancement: Request-level tracking
final readonly class ComponentRequestTracker
{
    private int $componentsCreated = 0;
    private const MAX_COMPONENTS_PER_REQUEST = 100;

    public function track(ComponentId $id): void
    {
        $this->componentsCreated++;

        if ($this->componentsCreated > self::MAX_COMPONENTS_PER_REQUEST) {
            throw new TooManyComponentsException(
                "Request exceeded component limit: {$this->componentsCreated}"
            );
        }
    }
}

Troubleshooting

High Memory Usage

Symptoms:

  • PHP memory limit errors
  • Slow response times
  • Cache growing too large

Diagnosis:

// Check cache size
$stats = $cacheManager->getStats($component);
// Look at 'age_seconds' - old caches not expiring?

// Monitor per-request component creation
error_log("Components created this request: " . count($componentIds));

Solutions:

  1. Reduce Cache TTL:
public function getCacheTTL(): Duration
{
    return Duration::fromMinutes(1);  // Shorter TTL
}
  1. Implement Cache Tags:
public function getCacheTags(): array
{
    return ['user:' . $this->userId, 'dashboard'];
}

// Invalidate by tag when data changes
$registry->invalidateCacheByTag('user:123');
  1. Use Conditional Caching:
public function shouldCache(): bool
{
    // Only cache for non-admin users
    return !$this->user->isAdmin();
}
  1. Clear Old Caches:
# Cron job for cleanup
*/30 * * * * php console.php cache:clear --tags=livecomponents

Memory Leaks

Potential Issues:

  • Event listeners not unsubscribed
  • Database connections in lifecycle hooks
  • Large closures in component state

Prevention:

final readonly class SafeComponent implements LiveComponentContract, LifecycleAware
{
    public function onMount(): void
    {
        // ✅ Subscribe to events
        $this->eventBus->subscribe('user.updated', $this->handleUserUpdate(...));
    }

    public function onDestroy(): void
    {
        // ✅ ALWAYS unsubscribe
        $this->eventBus->unsubscribe('user.updated', $this->handleUserUpdate(...));
    }
}

Monitoring

Component Metrics:

  • livecomponent.created.count - Components created per request
  • livecomponent.render.duration_ms - Render time distribution
  • livecomponent.cache.hit_rate - Cache effectiveness

Memory Metrics:

  • php.memory.usage_bytes - Current memory usage
  • php.memory.peak_bytes - Peak memory per request
  • cache.size_bytes - Total cache size

Alert Thresholds:

  • Memory usage > 80% of limit
  • Components per request > 50
  • Cache hit rate < 50%
  • Render time > 200ms (p95)

Production Configuration

// config/cache.php
return [
    'livecomponents' => [
        'default_ttl' => 300,        // 5 minutes
        'max_cache_size' => '100MB', // Per-driver limit
        'cleanup_interval' => 3600,  // 1 hour
        'enable_metrics' => true
    ]
];

Future Enhancements

Planned Improvements

  1. Request-Level Component Tracking

    • Track component creation count
    • Enforce per-request limits
    • Alert on threshold violations
  2. Memory Usage Profiling

    • Component memory footprint tracking
    • Automatic large component detection
    • Performance regression alerts
  3. Intelligent Cache Eviction

    • LRU eviction when cache full
    • Prioritize by component usage frequency
    • Automatic TTL adjustment based on hit rate
  4. Component Lifecycle Monitoring

    • Track component lifetime
    • Detect components never destroyed
    • Memory leak detection

Summary

Current State: Memory management is solid

  • No instance caches
  • TTL-based rendering cache
  • Framework cache handles underlying memory

No Immediate Action Required

  • Architecture is already memory-safe
  • Follow best practices above
  • Implement monitoring for production

⚠️ Future Work: Request-level limits and enhanced monitoring (Phase 5 - Observability)