Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,231 @@
<?php
declare(strict_types=1);
// Test logic for eager loading without mocking complex dependencies
test('eager loading performance simulation shows query reduction', function () {
// Simulate N+1 problem vs eager loading performance
// Scenario: 100 users, each with posts and profile
$userCount = 100;
$avgPostsPerUser = 5;
$profilePerUser = 1;
// N+1 Problem Simulation
$n1QueriesLazy = 1 + ($userCount * 2); // 1 query for users + 1 query per user for posts + 1 query per user for profile
// Eager Loading Simulation
$eagerQueries = 1 + 2; // 1 query for users + 1 batch query for posts + 1 batch query for profiles
$queryReduction = ($n1QueriesLazy - $eagerQueries) / $n1QueriesLazy;
expect($eagerQueries)->toBeLessThan($n1QueriesLazy);
expect($queryReduction)->toBeGreaterThan(0.95); // Over 95% query reduction
// Real numbers: 201 queries vs 3 queries = 98.5% reduction!
});
test('batch loading logic groups related entities correctly', function () {
// Simulate the batch loading grouping logic
// Users data
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
['id' => 3, 'name' => 'Charlie'],
];
// Posts data (simulating database result)
$allPosts = [
['id' => 1, 'user_id' => 1, 'title' => 'Alice Post 1'],
['id' => 2, 'user_id' => 1, 'title' => 'Alice Post 2'],
['id' => 3, 'user_id' => 2, 'title' => 'Bob Post 1'],
['id' => 4, 'user_id' => 3, 'title' => 'Charlie Post 1'],
['id' => 5, 'user_id' => 3, 'title' => 'Charlie Post 2'],
['id' => 6, 'user_id' => 3, 'title' => 'Charlie Post 3'],
];
// Simulate batch loading grouping (what our implementation does)
$postsByUserId = [];
foreach ($allPosts as $post) {
$userId = $post['user_id'];
if (! isset($postsByUserId[$userId])) {
$postsByUserId[$userId] = [];
}
$postsByUserId[$userId][] = $post;
}
// Verify correct grouping
expect($postsByUserId[1])->toHaveCount(2); // Alice has 2 posts
expect($postsByUserId[2])->toHaveCount(1); // Bob has 1 post
expect($postsByUserId[3])->toHaveCount(3); // Charlie has 3 posts
// Verify no posts are lost
$totalPosts = array_sum(array_map('count', $postsByUserId));
expect($totalPosts)->toBe(count($allPosts));
// Verify all users can get their posts
foreach ($users as $user) {
$userId = $user['id'];
$userPosts = $postsByUserId[$userId] ?? [];
// Each post should belong to the correct user
foreach ($userPosts as $post) {
expect($post['user_id'])->toBe($userId);
}
}
});
test('belongsTo relation batching reduces queries', function () {
// Simulate belongsTo relation (posts belonging to categories)
$posts = [
['id' => 1, 'title' => 'Post 1', 'category_id' => 1],
['id' => 2, 'title' => 'Post 2', 'category_id' => 2],
['id' => 3, 'title' => 'Post 3', 'category_id' => 1],
['id' => 4, 'title' => 'Post 4', 'category_id' => 3],
['id' => 5, 'title' => 'Post 5', 'category_id' => 2],
];
// Without batching: 1 query per post for category = 5 queries
$lazyQueries = count($posts);
// With batching: Collect all unique category_ids, then 1 IN query
$categoryIds = array_unique(array_column($posts, 'category_id'));
$batchQueries = 1; // Single IN query: SELECT * FROM categories WHERE id IN (1,2,3)
expect($batchQueries)->toBeLessThan($lazyQueries);
expect(count($categoryIds))->toBeLessThan(count($posts)); // Proof that we're reducing queries
// Simulate batch loading result
$categories = [
['id' => 1, 'name' => 'Tech'],
['id' => 2, 'name' => 'Science'],
['id' => 3, 'name' => 'Art'],
];
// Index by ID for fast lookup (what our implementation does)
$categoriesById = [];
foreach ($categories as $category) {
$categoriesById[$category['id']] = $category;
}
// Verify we can resolve all post categories
foreach ($posts as $post) {
$categoryId = $post['category_id'];
expect($categoriesById)->toHaveKey($categoryId);
expect($categoriesById[$categoryId]['id'])->toBe($categoryId);
}
});
test('one-to-one relation batching works correctly', function () {
// Simulate one-to-one relation (users with profiles)
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
['id' => 3, 'name' => 'Charlie'],
];
$profiles = [
['id' => 1, 'user_id' => 1, 'bio' => 'Alice bio'],
['id' => 2, 'user_id' => 2, 'bio' => 'Bob bio'],
['id' => 3, 'user_id' => 3, 'bio' => 'Charlie bio'],
];
// Batch loading: Single query with IN clause
$userIds = array_column($users, 'id');
$batchQuery = "SELECT * FROM profiles WHERE user_id IN (" . implode(',', $userIds) . ")";
expect($batchQuery)->toContain('IN (1,2,3)');
// Group profiles by user_id (one-to-one, so each user has max 1 profile)
$profileByUserId = [];
foreach ($profiles as $profile) {
$profileByUserId[$profile['user_id']] = $profile;
}
// Verify one-to-one relationship
expect($profileByUserId)->toHaveCount(3);
expect($profileByUserId[1]['bio'])->toBe('Alice bio');
expect($profileByUserId[2]['bio'])->toBe('Bob bio');
expect($profileByUserId[3]['bio'])->toBe('Charlie bio');
});
test('eager loading handles missing relations gracefully', function () {
// Test scenario where some entities don't have relations
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
['id' => 3, 'name' => 'Charlie'],
];
// Only some users have posts
$posts = [
['id' => 1, 'user_id' => 1, 'title' => 'Alice Post'],
['id' => 2, 'user_id' => 3, 'title' => 'Charlie Post'],
// Bob (user_id: 2) has no posts
];
// Group posts by user_id
$postsByUserId = [];
foreach ($posts as $post) {
$userId = $post['user_id'];
if (! isset($postsByUserId[$userId])) {
$postsByUserId[$userId] = [];
}
$postsByUserId[$userId][] = $post;
}
// Assign relations to users
$usersWithPosts = [];
foreach ($users as $user) {
$userId = $user['id'];
$usersWithPosts[] = [
'user' => $user,
'posts' => $postsByUserId[$userId] ?? [], // Default to empty array if no posts
];
}
// Verify handling of missing relations
expect($usersWithPosts[0]['posts'])->toHaveCount(1); // Alice has 1 post
expect($usersWithPosts[1]['posts'])->toHaveCount(0); // Bob has 0 posts
expect($usersWithPosts[2]['posts'])->toHaveCount(1); // Charlie has 1 post
// Verify no user is missing from result
expect($usersWithPosts)->toHaveCount(3);
});
test('complex eager loading scenario performance calculation', function () {
// Real-world scenario: Blog system with nested relations
$postCount = 50;
$avgCommentsPerPost = 8;
$avgTagsPerPost = 3;
$avgCategoriesPerPost = 1; // belongsTo relation
// Without eager loading (N+1 problem)
$lazyQueries = 1; // Posts query
$lazyQueries += $postCount; // 1 query per post for category (belongsTo)
$lazyQueries += $postCount; // 1 query per post for comments (hasMany)
$lazyQueries += $postCount; // 1 query per post for tags (hasMany)
// Total: 1 + 50 + 50 + 50 = 151 queries
// With eager loading
$eagerQueries = 1; // Posts query
$eagerQueries += 1; // Batch query for all categories (IN clause)
$eagerQueries += 1; // Batch query for all comments (WHERE post_id IN ...)
$eagerQueries += 1; // Batch query for all tags (JOIN with pivot table)
// Total: 4 queries
$performanceGain = ($lazyQueries - $eagerQueries) / $lazyQueries;
expect($eagerQueries)->toBe(4);
expect($lazyQueries)->toBe(151);
expect($performanceGain)->toBeGreaterThan(0.97); // Over 97% query reduction!
// Database load reduction
$loadReduction = $lazyQueries / $eagerQueries;
expect($loadReduction)->toBeGreaterThan(35); // 37.75x fewer queries
});