fix: resolve RedisCache array offset error and improve discovery diagnostics

- Fix RedisCache driver to handle MGET failures gracefully with fallback
- Add comprehensive discovery context comparison debug tools
- Identify root cause: WEB context discovery missing 166 items vs CLI
- WEB context missing RequestFactory class entirely (52 vs 69 commands)
- Improved exception handling with detailed binding diagnostics
This commit is contained in:
2025-09-12 20:05:18 +02:00
parent 8040d3e7a5
commit e30753ba0e
46990 changed files with 10789682 additions and 89639 deletions

View File

@@ -24,6 +24,7 @@ final readonly class DiscoveryCacheIdentifiers
/**
* Create cache key for discovery results based on paths, scan type, and execution context
* @param string[] $paths
*/
public static function discoveryKey(array $paths, ScanType $scanType, ?string $context = null): CacheKey
{
@@ -36,6 +37,7 @@ final readonly class DiscoveryCacheIdentifiers
/**
* Create cache key for full discovery
* @param string[] $paths
*/
public static function fullDiscoveryKey(array $paths, ?string $context = null): CacheKey
{
@@ -44,6 +46,7 @@ final readonly class DiscoveryCacheIdentifiers
/**
* Create cache key for incremental discovery
* @param string[] $paths
*/
public static function incrementalDiscoveryKey(array $paths, ?string $context = null): CacheKey
{

View File

@@ -10,7 +10,7 @@ use App\Framework\Console\ConsoleInput;
use App\Framework\Console\ConsoleOutput;
use App\Framework\Core\PathProvider;
use App\Framework\DateTime\Clock;
use App\Framework\Discovery\DiscoveryCache;
use App\Framework\Discovery\Storage\DiscoveryCacheManager;
/**
* Unified console commands for clearing discovery-related caches
@@ -23,9 +23,10 @@ use App\Framework\Discovery\DiscoveryCache;
final readonly class ClearDiscoveryCache
{
public function __construct(
private DiscoveryCacheManager $discoveryCacheManager,
private ConsoleOutput $output,
private Cache $cache,
private Clock $clock,
private ConsoleOutput $output,
private PathProvider $pathProvider
) {
}
@@ -36,14 +37,12 @@ final readonly class ClearDiscoveryCache
$this->output->writeLine('Clearing Discovery cache...');
try {
$discoveryCache = new DiscoveryCache($this->cache, $this->clock);
if ($discoveryCache->flush()) {
if ($this->discoveryCacheManager->clearAll()) {
$this->output->writeLine('<success>Discovery cache cleared successfully!</success>');
return 0;
} else {
$this->output->writeLine('<error>Failed to clear Discovery cache - flush returned false</error>');
$this->output->writeLine('<error>Failed to clear Discovery cache - clearAll returned false</error>');
return 1;
}
@@ -61,9 +60,8 @@ final readonly class ClearDiscoveryCache
$success = true;
// Clear discovery cache
$discoveryCache = new DiscoveryCache($this->cache, $this->clock);
if ($discoveryCache->flush()) {
// Clear discovery cache using the cache manager
if ($this->discoveryCacheManager->clearAll()) {
$this->output->writeLine('✓ Discovery cache cleared');
} else {
$this->output->writeLine('✗ Failed to clear Discovery cache');

View File

@@ -48,6 +48,7 @@ final readonly class CacheEvictionEvent
/**
* Convert to array for serialization
* @return array<string, mixed>
*/
public function toArray(): array
{

View File

@@ -47,6 +47,7 @@ final readonly class CacheMissEvent
/**
* Convert to array for serialization
* @return array<string, mixed>
*/
public function toArray(): array
{

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Framework\Discovery\Events;
use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Discovery\Results\DiscoveryResults;
use App\Framework\Discovery\Results\DiscoveryRegistry;
use App\Framework\Discovery\ValueObjects\ScanType;
use Throwable;
@@ -16,7 +16,7 @@ final readonly class DiscoveryFailedEvent
{
public function __construct(
public Throwable $exception,
public ?DiscoveryResults $partialResults,
public ?DiscoveryRegistry $partialResults,
public ScanType $scanType,
public Timestamp $timestamp
) {
@@ -33,7 +33,7 @@ final readonly class DiscoveryFailedEvent
'error' => $this->exception->getMessage(),
'error_type' => get_class($this->exception),
'has_partial_results' => $this->hasPartialResults(),
'partial_files_count' => $this->partialResults ? count($this->partialResults->toArray()) : 0,
'partial_files_count' => $this->partialResults ? $this->partialResults->count() : 0,
'scan_type' => $this->scanType->value,
'timestamp' => $this->timestamp->toFloat(),
];

View File

@@ -192,4 +192,12 @@ final readonly class DiscoveryRegistry implements Countable
{
return $this->count();
}
/**
* Get the attributes registry
*/
public function attributes(): AttributeRegistry
{
return $this->attributes;
}
}

View File

@@ -27,6 +27,7 @@ final class TemplateRegistry implements Countable
/**
* Convert to array for cache serialization
* @return array<string, mixed>
*/
public function toArray(): array
{

View File

@@ -41,8 +41,10 @@ final class DiscoveryCacheManager
private const string CACHE_PREFIX = 'discovery:';
private const int DEFAULT_TTL_HOURS = 24;
/** @var array<string, array<string, mixed>> */
private array $cacheMetrics = [];
/** @var array<string, array<string, mixed>> */
private array $accessPatterns = [];
private CacheLevel $currentLevel = CacheLevel::NORMAL;
@@ -224,9 +226,12 @@ final class DiscoveryCacheManager
/**
* Get enhanced cache health status with memory awareness
*
* @return array<string, mixed>
*/
public function getHealthStatus(): array
{
/** @var array<string, mixed> */
$baseStatus = [
'cache_driver' => get_class($this->cache),
'ttl_hours' => $this->ttlHours,
@@ -275,6 +280,8 @@ final class DiscoveryCacheManager
/**
* Perform memory pressure management
*
* @return array<string, mixed>
*/
public function performMemoryPressureManagement(): array
{
@@ -283,6 +290,7 @@ final class DiscoveryCacheManager
}
$memoryStatus = $this->memoryManager->getMemoryStatus('pressure_management');
/** @var array<int, string> */
$actions = [];
if ($memoryStatus->status === MemoryStatus::CRITICAL) {
@@ -430,6 +438,7 @@ final class DiscoveryCacheManager
// Emit compression event
$this->emitCompressionEvent($originalSize, $compressedSize, $compressionLevel);
/** @var array<string, mixed> */
return [
'__discovery_compressed__' => true,
'data' => $compressed,
@@ -531,6 +540,7 @@ final class DiscoveryCacheManager
$timeWindow = 3600; // 1 hour
$currentTime = $this->clock->time();
/** @var array<int, int> */
$recentAccesses = array_filter(
$pattern['access_history'],
fn ($timestamp) => ($currentTime - $timestamp) <= $timeWindow

View File

@@ -23,11 +23,11 @@ use App\Framework\Reflection\ReflectionProvider;
* Provides helper methods for testing Discovery components
* with mock data, performance validation, and quality checks.
*/
final class DiscoveryTestHelper
final readonly class DiscoveryTestHelper
{
public function __construct(
private readonly Clock $clock,
private readonly ?Logger $logger = null
private Clock $clock,
private ?Logger $logger = null
) {
}
@@ -67,14 +67,14 @@ final class DiscoveryTestHelper
public function createTestConfiguration(array $overrides = []): DiscoveryConfiguration
{
return new DiscoveryConfiguration(
paths: $overrides['paths'] ?? ['/tmp/test/src'],
useCache: $overrides['use_cache'] ?? true,
cacheTimeout: Duration::fromHours($overrides['cache_timeout_hours'] ?? 1),
memoryLimitMB: $overrides['memory_limit_mb'] ?? 128,
maxFilesPerBatch: $overrides['max_files_per_batch'] ?? 50,
memoryPressureThreshold: $overrides['memory_pressure_threshold'] ?? 0.8,
enableMemoryMonitoring: $overrides['enable_memory_monitoring'] ?? true,
enablePerformanceTracking: $overrides['enable_performance_tracking'] ?? true
paths : $overrides['paths'] ?? ['/tmp/test/src'],
useCache : $overrides['use_cache'] ?? true,
cacheTimeout : Duration::fromHours($overrides['cache_timeout_hours'] ?? 1),
memoryLimitMB : $overrides['memory_limit_mb'] ?? 128,
enableMemoryMonitoring : $overrides['enable_memory_monitoring'] ?? true,
enablePerformanceTracking: $overrides['enable_performance_tracking'] ?? true,
maxFilesPerBatch : $overrides['max_files_per_batch'] ?? 50,
memoryPressureThreshold : $overrides['memory_pressure_threshold'] ?? 0.8
);
}
@@ -386,7 +386,7 @@ final class TestController
{
return \'Test Controller\';
}
#[Route(path: \'/test/{id}\', method: Method::GET)]
public function show(int $id): string
{

View File

@@ -145,6 +145,7 @@ final readonly class TemplateCollection implements Countable, IteratorAggregate
/**
* Get templates grouped by type
* @return array<string, self>
*/
public function groupByType(): array
{
@@ -165,6 +166,7 @@ final readonly class TemplateCollection implements Countable, IteratorAggregate
/**
* Get templates grouped by directory
* @return array<string, self>
*/
public function groupByDirectory(): array
{
@@ -186,6 +188,7 @@ final readonly class TemplateCollection implements Countable, IteratorAggregate
/**
* Get unique template names
* @return array<int, string>
*/
public function getUniqueNames(): array
{
@@ -196,6 +199,7 @@ final readonly class TemplateCollection implements Countable, IteratorAggregate
/**
* Get unique template types
* @return array<int, string>
*/
public function getUniqueTypes(): array
{