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:
278
src/Framework/Database/AsyncDatabaseBuilder.php
Normal file
278
src/Framework/Database/AsyncDatabaseBuilder.php
Normal file
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Database;
|
||||
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
|
||||
/**
|
||||
* Fluent Builder für AsyncDatabase Operations
|
||||
*
|
||||
* Vereinfacht die Erstellung von komplexen parallelen Database Operations
|
||||
*/
|
||||
final class AsyncDatabaseBuilder
|
||||
{
|
||||
private array $queries = [];
|
||||
|
||||
private ?Duration $timeout = null;
|
||||
|
||||
private bool $useTransaction = false;
|
||||
|
||||
public function __construct(
|
||||
private readonly AsyncDatabaseDecorator $db
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge SELECT Query hinzu
|
||||
*/
|
||||
public function select(string $key, string $sql, array $params = []): self
|
||||
{
|
||||
return $this->addQuery($key, $sql, $params, 'query');
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge SELECT One Query hinzu
|
||||
*/
|
||||
public function selectOne(string $key, string $sql, array $params = []): self
|
||||
{
|
||||
return $this->addQuery($key, $sql, $params, 'queryOne');
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge SELECT Column Query hinzu
|
||||
*/
|
||||
public function selectColumn(string $key, string $sql, array $params = []): self
|
||||
{
|
||||
return $this->addQuery($key, $sql, $params, 'queryColumn');
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge SELECT Scalar Query hinzu
|
||||
*/
|
||||
public function selectScalar(string $key, string $sql, array $params = []): self
|
||||
{
|
||||
return $this->addQuery($key, $sql, $params, 'queryScalar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge COUNT Query hinzu
|
||||
*/
|
||||
public function count(string $key, string $table, string $where = '1=1', array $params = []): self
|
||||
{
|
||||
$sql = "SELECT COUNT(*) FROM `$table` WHERE $where";
|
||||
|
||||
return $this->addQuery($key, $sql, $params, 'queryScalar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge SUM Query hinzu
|
||||
*/
|
||||
public function sum(string $key, string $table, string $column, string $where = '1=1', array $params = []): self
|
||||
{
|
||||
$sql = "SELECT COALESCE(SUM(`$column`), 0) FROM `$table` WHERE $where";
|
||||
|
||||
return $this->addQuery($key, $sql, $params, 'queryScalar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge AVG Query hinzu
|
||||
*/
|
||||
public function avg(string $key, string $table, string $column, string $where = '1=1', array $params = []): self
|
||||
{
|
||||
$sql = "SELECT COALESCE(AVG(`$column`), 0) FROM `$table` WHERE $where";
|
||||
|
||||
return $this->addQuery($key, $sql, $params, 'queryScalar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge MAX Query hinzu
|
||||
*/
|
||||
public function max(string $key, string $table, string $column, string $where = '1=1', array $params = []): self
|
||||
{
|
||||
$sql = "SELECT MAX(`$column`) FROM `$table` WHERE $where";
|
||||
|
||||
return $this->addQuery($key, $sql, $params, 'queryScalar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Füge MIN Query hinzu
|
||||
*/
|
||||
public function min(string $key, string $table, string $column, string $where = '1=1', array $params = []): self
|
||||
{
|
||||
$sql = "SELECT MIN(`$column`) FROM `$table` WHERE $where";
|
||||
|
||||
return $this->addQuery($key, $sql, $params, 'queryScalar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Setze Timeout für alle Queries
|
||||
*/
|
||||
public function withTimeout(Duration $timeout): self
|
||||
{
|
||||
$this->timeout = $timeout;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Führe alle Queries in einer Transaktion aus
|
||||
*/
|
||||
public function inTransaction(): self
|
||||
{
|
||||
$this->useTransaction = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Führe alle Queries parallel aus
|
||||
*/
|
||||
public function execute(): array
|
||||
{
|
||||
if (empty($this->queries)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($this->useTransaction) {
|
||||
return $this->executeInTransaction();
|
||||
}
|
||||
|
||||
if ($this->timeout !== null) {
|
||||
return $this->db->readAhead($this->queries, $this->timeout);
|
||||
}
|
||||
|
||||
return $this->db->aggregate($this->queries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Führe als Read-Ahead aus (mit Timeout Protection)
|
||||
*/
|
||||
public function executeAsReadAhead(): array
|
||||
{
|
||||
$timeout = $this->timeout ?? Duration::fromSeconds(10);
|
||||
|
||||
return $this->db->readAhead($this->queries, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Builder für Wiederverwendung
|
||||
*/
|
||||
public function reset(): self
|
||||
{
|
||||
$this->queries = [];
|
||||
$this->timeout = null;
|
||||
$this->useTransaction = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstelle neuen Builder
|
||||
*/
|
||||
public static function create(AsyncDatabaseDecorator $db): self
|
||||
{
|
||||
return new self($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper für Dashboard Metrics
|
||||
*/
|
||||
public function dashboardMetrics(): self
|
||||
{
|
||||
return $this
|
||||
->count('total_users', 'users')
|
||||
->count('active_users', 'users', 'status = ?', ['active'])
|
||||
->count('recent_orders', 'orders', 'created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)')
|
||||
->sum('daily_revenue', 'orders', 'total', 'created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)')
|
||||
->count('pending_orders', 'orders', 'status = ?', ['pending']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper für User Analytics
|
||||
*/
|
||||
public function userAnalytics(int $userId): self
|
||||
{
|
||||
return $this
|
||||
->selectOne('profile', 'SELECT id, name, email, created_at FROM users WHERE id = ?', [$userId])
|
||||
->count('total_orders', 'orders', 'user_id = ?', [$userId])
|
||||
->sum('total_spent', 'orders', 'total', 'user_id = ?', [$userId])
|
||||
->selectOne('last_order', 'SELECT id, total, created_at FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 1', [$userId])
|
||||
->count('login_count', 'user_sessions', 'user_id = ? AND created_at > DATE_SUB(NOW(), INTERVAL 30 DAY)', [$userId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper für Product Analytics
|
||||
*/
|
||||
public function productAnalytics(int $productId): self
|
||||
{
|
||||
return $this
|
||||
->selectOne('product', 'SELECT * FROM products WHERE id = ?', [$productId])
|
||||
->count('total_sales', 'order_items oi JOIN orders o ON oi.order_id = o.id', 'oi.product_id = ?', [$productId])
|
||||
->sum('revenue', 'order_items oi JOIN orders o ON oi.order_id = o.id', 'oi.price * oi.quantity', 'oi.product_id = ?', [$productId])
|
||||
->avg('avg_rating', 'reviews', 'rating', 'product_id = ?', [$productId])
|
||||
->count('review_count', 'reviews', 'product_id = ?', [$productId])
|
||||
->selectScalar('current_stock', 'SELECT quantity FROM inventory WHERE product_id = ?', [$productId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper für System Health Metrics
|
||||
*/
|
||||
public function systemHealth(): self
|
||||
{
|
||||
return $this
|
||||
->count('error_logs_1h', 'error_logs', 'created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)')
|
||||
->count('slow_queries_1h', 'slow_query_log', 'start_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)')
|
||||
->count('active_sessions', 'user_sessions', 'created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)')
|
||||
->selectScalar('db_size', "SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) FROM information_schema.TABLES WHERE table_schema = DATABASE()")
|
||||
->count('failed_jobs', 'job_queue', 'status = ? AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)', ['failed']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper für E-commerce Analytics
|
||||
*/
|
||||
public function ecommerceAnalytics(\DateTime $date): self
|
||||
{
|
||||
$dateStr = $date->format('Y-m-d');
|
||||
|
||||
return $this
|
||||
->count('daily_orders', 'orders', 'DATE(created_at) = ?', [$dateStr])
|
||||
->sum('daily_revenue', 'orders', 'total', 'DATE(created_at) = ?', [$dateStr])
|
||||
->count('new_customers', 'users', 'DATE(created_at) = ?', [$dateStr])
|
||||
->selectScalar('avg_order_value', 'SELECT AVG(total) FROM orders WHERE DATE(created_at) = ?', [$dateStr])
|
||||
->select('top_products', 'SELECT p.name, SUM(oi.quantity) as sales FROM order_items oi JOIN products p ON oi.product_id = p.id JOIN orders o ON oi.order_id = o.id WHERE DATE(o.created_at) = ? GROUP BY p.id ORDER BY sales DESC LIMIT 10', [$dateStr]);
|
||||
}
|
||||
|
||||
private function addQuery(string $key, string $sql, array $params, string $method): self
|
||||
{
|
||||
$this->queries[$key] = [
|
||||
'sql' => $sql,
|
||||
'params' => $params,
|
||||
'method' => $method,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function executeInTransaction(): array
|
||||
{
|
||||
if ($this->timeout !== null) {
|
||||
return $this->db->transactionWithTimeout(function ($db) {
|
||||
return $db->aggregate($this->queries);
|
||||
}, $this->timeout);
|
||||
}
|
||||
|
||||
return $this->db->transactionWithTimeout(function ($db) {
|
||||
return $db->aggregate($this->queries);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Extension function for easier access
|
||||
if (! function_exists('asyncDb')) {
|
||||
function asyncDb(AsyncDatabaseDecorator $db): AsyncDatabaseBuilder
|
||||
{
|
||||
return AsyncDatabaseBuilder::create($db);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user