250 lines
8.4 KiB
PHP
250 lines
8.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\WeldLogTriggers;
|
|
|
|
use Illuminate\Support\Facades\Log;
|
|
use App\Helpers\TransactionHelper;
|
|
|
|
/**
|
|
* WeldLog Trigger Manager
|
|
*
|
|
* Manages the execution of all weld log triggers
|
|
* Handles trigger execution order, timing, and error handling
|
|
*/
|
|
class WeldLogTriggerManager
|
|
{
|
|
/**
|
|
* @var WeldLogTriggerRegistry Trigger registry
|
|
*/
|
|
protected $registry;
|
|
|
|
/**
|
|
* @var float Overall start time
|
|
*/
|
|
protected $overallStartTime;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param WeldLogTriggerRegistry $registry
|
|
*/
|
|
public function __construct(WeldLogTriggerRegistry $registry)
|
|
{
|
|
$this->registry = $registry;
|
|
}
|
|
|
|
/**
|
|
* Execute all applicable triggers
|
|
*
|
|
* @param object $weldLogData Current weld log data
|
|
* @param object|null $beforeData Previous weld log data (null for new records)
|
|
* @param array $changedFields List of changed field names
|
|
* @param bool $isNewRecord Whether this is a new record
|
|
* @return array Execution results
|
|
*/
|
|
public function executeTriggers(
|
|
$weldLogData,
|
|
$beforeData = null,
|
|
array $changedFields = [],
|
|
bool $isNewRecord = false,
|
|
?string $action = null
|
|
): array {
|
|
$this->overallStartTime = microtime(true);
|
|
|
|
Log::info("=== WELD LOG SAVE TRIGGER STARTED ===", [
|
|
'weld_log_id' => $weldLogData->id,
|
|
'timestamp' => now()->toDateTimeString(),
|
|
'is_new_record' => $isNewRecord,
|
|
'changed_fields_count' => count($changedFields),
|
|
'changed_fields' => $changedFields,
|
|
'action' => $action,
|
|
'memory_usage_start' => round(memory_get_usage(true) / 1024 / 1024, 2) . ' MB'
|
|
]);
|
|
|
|
// Set database timeouts and memory limits
|
|
TransactionHelper::setDatabaseTimeouts(300, 600, 600);
|
|
ini_set('memory_limit', '2G');
|
|
ini_set('max_execution_time', 600); // 10 minutes
|
|
|
|
$results = [];
|
|
$triggers = $this->registry->getTriggersInOrder();
|
|
|
|
Log::info("Total triggers registered: " . count($triggers), [
|
|
'trigger_names' => array_map(function($t) { return $t->getName(); }, $triggers)
|
|
]);
|
|
|
|
foreach ($triggers as $trigger) {
|
|
// Check if trigger should run
|
|
if (!$trigger->shouldRun($changedFields, $isNewRecord)) {
|
|
Log::info("Skipping trigger: {$trigger->getName()}", [
|
|
'reason' => 'shouldRun returned false',
|
|
'order' => $trigger->getOrder(),
|
|
'dependent_fields' => $trigger->getDependentFields()
|
|
]);
|
|
|
|
$results[$trigger->getName()] = [
|
|
'skipped' => true,
|
|
'reason' => 'shouldRun returned false'
|
|
];
|
|
continue;
|
|
}
|
|
|
|
// Execute sync or async
|
|
if ($trigger->isAsync()) {
|
|
$this->executeAsync($trigger, $weldLogData, $beforeData, $changedFields);
|
|
$results[$trigger->getName()] = [
|
|
'queued' => true,
|
|
'execution' => 'async'
|
|
];
|
|
} else {
|
|
try {
|
|
$result = $trigger->execute($weldLogData, $beforeData, [
|
|
'changed_fields' => $changedFields,
|
|
'is_new_record' => $isNewRecord,
|
|
'action' => $action
|
|
]);
|
|
$results[$trigger->getName()] = array_merge($result, [
|
|
'executed' => true,
|
|
'execution' => 'sync'
|
|
]);
|
|
} catch (\Throwable $th) {
|
|
Log::error("Trigger execution failed: {$trigger->getName()}", [
|
|
'error' => $th->getMessage(),
|
|
'file' => $th->getFile(),
|
|
'line' => $th->getLine(),
|
|
'trace' => $th->getTraceAsString()
|
|
]);
|
|
|
|
$results[$trigger->getName()] = [
|
|
'executed' => false,
|
|
'error' => $th->getMessage(),
|
|
'execution' => 'sync'
|
|
];
|
|
|
|
// Re-throw critical errors, log others
|
|
if ($this->isCriticalTrigger($trigger->getName())) {
|
|
throw $th;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->logOverallCompletion($weldLogData->id, $results);
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Execute trigger asynchronously (via queue)
|
|
*
|
|
* @param \App\Services\WeldLogTriggers\Contracts\WeldLogTriggerInterface $trigger
|
|
* @param object $weldLogData
|
|
* @param object|null $beforeData
|
|
* @param array $changedFields
|
|
*/
|
|
protected function executeAsync($trigger, $weldLogData, $beforeData, $changedFields)
|
|
{
|
|
// Future implementation: Dispatch job to queue
|
|
// \App\Jobs\WeldLogTriggerJob::dispatch(
|
|
// get_class($trigger),
|
|
// $weldLogData->id,
|
|
// $beforeData,
|
|
// $changedFields
|
|
// );
|
|
|
|
Log::info("Trigger queued (async execution): {$trigger->getName()}", [
|
|
'weld_log_id' => $weldLogData->id,
|
|
'note' => 'Async execution not yet implemented, falling back to sync'
|
|
]);
|
|
|
|
// Fallback to sync execution for now
|
|
try {
|
|
$trigger->execute($weldLogData, $beforeData, [
|
|
'changed_fields' => $changedFields,
|
|
'is_new_record' => false,
|
|
// $action is not available here in the current signature, but async isn't used yet anyway
|
|
]);
|
|
} catch (\Throwable $th) {
|
|
Log::error("Async trigger execution failed: {$trigger->getName()}", [
|
|
'error' => $th->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if a trigger is critical (should stop execution on failure)
|
|
*
|
|
* @param string $triggerName
|
|
* @return bool
|
|
*/
|
|
protected function isCriticalTrigger(string $triggerName): bool
|
|
{
|
|
// Define which triggers are critical
|
|
$criticalTriggers = [
|
|
'Spool Status Changer',
|
|
'Line Lists Update',
|
|
'NDE Matrix Update',
|
|
'Construction Paint Logs Sync',
|
|
'Paint Follow Ups Sync',
|
|
];
|
|
|
|
return in_array($triggerName, $criticalTriggers);
|
|
}
|
|
|
|
/**
|
|
* Log overall execution completion
|
|
*
|
|
* @param int $weldLogId
|
|
* @param array $results
|
|
*/
|
|
protected function logOverallCompletion($weldLogId, array $results)
|
|
{
|
|
$overallDuration = round((microtime(true) - $this->overallStartTime) * 1000, 2);
|
|
|
|
// Count execution statistics
|
|
$executedCount = 0;
|
|
$skippedCount = 0;
|
|
$queuedCount = 0;
|
|
$failedCount = 0;
|
|
|
|
foreach ($results as $triggerName => $result) {
|
|
if (isset($result['executed']) && $result['executed']) {
|
|
$executedCount++;
|
|
} elseif (isset($result['skipped']) && $result['skipped']) {
|
|
$skippedCount++;
|
|
} elseif (isset($result['queued']) && $result['queued']) {
|
|
$queuedCount++;
|
|
} elseif (isset($result['executed']) && !$result['executed']) {
|
|
$failedCount++;
|
|
}
|
|
}
|
|
|
|
Log::info("=== WELD LOG SAVE TRIGGER COMPLETED ===", [
|
|
'weld_log_id' => $weldLogId,
|
|
'timestamp' => now()->toDateTimeString(),
|
|
'total_execution_time_ms' => $overallDuration,
|
|
'total_execution_time_sec' => round($overallDuration / 1000, 3),
|
|
'peak_memory_usage_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
|
|
'final_memory_usage_mb' => round(memory_get_usage(true) / 1024 / 1024, 2),
|
|
'statistics' => [
|
|
'total_triggers' => count($results),
|
|
'executed' => $executedCount,
|
|
'skipped' => $skippedCount,
|
|
'queued' => $queuedCount,
|
|
'failed' => $failedCount
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get the registry instance
|
|
*
|
|
* @return WeldLogTriggerRegistry
|
|
*/
|
|
public function getRegistry(): WeldLogTriggerRegistry
|
|
{
|
|
return $this->registry;
|
|
}
|
|
}
|
|
|