# Save Trigger System - Complete Guide ## What is Save Trigger System? The Save Trigger System is like having a smart assistant that automatically keeps all your project data organized and synchronized. When you save or update information in one place, it automatically updates related information in other places without you having to do anything extra. ### Simple Analogy Think of it like a smart spreadsheet that automatically updates all related cells when you change one value. For example: - **You update a welding log** β†’ System automatically updates test packages, paint schedules, and material lists - **You change a line specification** β†’ System updates all related construction logs and quality control records - **You modify a test package** β†’ System updates status reports and progress tracking ## Which Modules Have Save Triggers? The Save Trigger System is active in the following key modules: ### πŸ—οΈ **Construction & Engineering Modules** - **Line Lists** - When you update line specifications, it syncs with: - Weld logs - Paint matrices - NDE matrices - Construction paint logs - Paint follow-ups - **Weld Logs** - When you update welding information, it updates: - Test packages - NDE matrices - Paint follow-ups - Construction paint logs - Handover records ### 🎨 **Paint & Coating Modules** - **Paint Systems** - When you update paint specifications, it syncs with: - Paint matrices - Paint follow-ups - Construction paint logs - **Color Systems** - When you update color codes, it updates: - Paint matrices - Paint follow-ups - Construction paint logs ### πŸ“‹ **Testing & Quality Modules** - **Test Packages** - When you update test package information, it updates: - Test package base statuses - Welding status calculations - Progress tracking - **Test Pack Base Statuses** - When you update status information, it syncs with: - Test packages - ISO drawings - Priority calculations ### πŸ”§ **Support & Material Modules** - **Supports** - When you update support information, it syncs with: - Material take-off sheets - Construction logs - **MTOs (Material Take-Off Sheets)** - When you update material information, it updates: - Support structures - Material lists ### πŸ“Š **Other Modules** - **NDE Matrices** - Updates quality control records - **Repair Logs** - Updates test package statuses - **Punch Lists** - Updates construction progress - **Subcontractors** - Updates related project records ## How Does It Work? (Step by Step) ### Step 1: User Saves Data When you save or update information in any of these modules through the web interface: ``` User clicks "Save" β†’ AdminController receives the data β†’ System prepares background job ``` ### Step 2: Background Job Creation Instead of processing everything immediately (which could slow down your application), the system creates a background job: ``` AdminController β†’ Creates ExecuteSaveTriggerJob β†’ Job goes to queue β†’ User gets immediate response ``` ### Step 3: Queue Processing The job waits in a queue (like a waiting line) and gets processed by a background worker: ``` Queue Worker picks up job β†’ Executes Save Trigger file β†’ Updates related tables β†’ Job completed ``` ### Step 4: Data Synchronization The Save Trigger file contains specific business logic that updates all related information: ``` Trigger File β†’ Reads updated data β†’ Finds related records β†’ Updates them automatically ``` ## Real-World Example: Weld Log Update Let's say you update a weld log entry with new information: ### What You Do: 1. Open weld log entry 2. Change the spool number from "SPL-001" to "SPL-002" 3. Click "Save" ### What the System Does Automatically: 1. **Immediate Response**: You get confirmation that your change was saved 2. **Background Processing**: System creates a job to update related data 3. **Test Package Update**: Updates test package status and progress 4. **Paint Schedule Update**: Updates paint follow-up records 5. **Quality Control Update**: Updates NDE matrix records 6. **Construction Log Update**: Updates construction paint logs 7. **Handover Update**: Updates handover records ### Result: All related information is automatically synchronized without you having to update 5 different places manually. ## Technical Architecture ### Queue System Flow ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User Saves β”‚ β”‚ Job Created β”‚ β”‚ Job Queued β”‚ β”‚ Data in UI │───▢│ & Dispatched │───▢│ in Database β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β–Ό β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User Gets β”‚ β”‚ Queue Worker β”‚ β”‚ Job Executed β”‚ β”‚ Immediate β”‚ β”‚ Picks Up Job β”‚ β”‚ in Background β”‚ β”‚ Response β”‚ β”‚ from Queue β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Trigger File β”‚ β”‚ Data Updated β”‚ β”‚ Application β”‚ β”‚ Executed β”‚ β”‚ in Related β”‚ β”‚ Continues β”‚ β”‚ Asynchronouslyβ”‚ β”‚ Tables β”‚ β”‚ Responsively β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Core Components 1. **ExecuteSaveTriggerJob** - The main job class that handles trigger execution 2. **SaveTrigger Directory** - Contains individual trigger files for each table 3. **AdminController Integration** - Dispatches jobs after CRUD operations 4. **Queue System** - Handles asynchronous execution ### Directory Structure ``` app/ β”œβ”€β”€ Jobs/ β”‚ └── ExecuteSaveTriggerJob.php β”œβ”€β”€ Http/Controllers/ β”‚ β”œβ”€β”€ AdminController.php β”‚ └── SaveTrigger/ β”‚ β”œβ”€β”€ weld_logs.php β”‚ β”œβ”€β”€ test_packages.php β”‚ β”œβ”€β”€ supports.php β”‚ β”œβ”€β”€ m_t_o_s.php β”‚ β”œβ”€β”€ i_t_p_s.php β”‚ └── [other_table_triggers].php ``` ## How It Works (Technical Details) ### 1. Trigger Dispatch When a record is saved or updated through the AdminController, the system automatically dispatches a job: ```php // In AdminController::saveJson() ExecuteSaveTriggerJob::dispatch( $tableName, // Target table name $request->all(), // Request data $request['key'], // Record ID $request['values'] ?? null, // Updated values $beforeData // Original data before update ); ``` ### 2. Job Execution The `ExecuteSaveTriggerJob` handles the execution: ```php public function handle(): void { $path = app_path("Http/Controllers/SaveTrigger/{$this->tableName}.php"); if (file_exists($path)) { // Make variables globally accessible in trigger file $tableName = $this->tableName; $request = $this->requestData; $key = $this->key; $values = $this->values; $beforeData = $this->beforeData; // Include and execute trigger file include($path); } } ``` ### 3. Trigger File Structure Each trigger file follows a specific pattern: ```php where("id", $request['key'])->first(); // 2. Define unique fields for upsert operations $uniqueFields = [ 'field1' => $data->value1, 'field2' => $data->value2, ]; // 3. Define data to update/insert $dataToUpdate = [ 'target_field1' => $data->source_field1, 'target_field2' => $data->source_field2, ]; // 4. Execute upsert operation echo db('target_table')->updateOrInsert($uniqueFields, $dataToUpdate); ?> ``` ## Key Features ### 1. Asynchronous Execution - Triggers run in the background using Laravel's queue system - Main application flow is not blocked - Failed jobs can be retried automatically ### 2. Telescope Integration The job includes Telescope monitoring capabilities: ```php public function getDescription(): string { $action = $this->key ? 'Update' : 'Create'; return "Execute Save Trigger for {$this->tableName} table - {$action} operation"; } public function tags(): array { $action = $this->key ? 'Update' : 'Create'; return [ "SaveTrigger:{$this->tableName}", "Action:{$action}", "Table:{$this->tableName}" ]; } ``` ### 3. Change Detection Advanced triggers can detect which fields have changed: ```php // Detect changed fields $changedFields = []; $dataArray = (array) $data; foreach ($dataArray as $key => $value) { if (isset($beforeData->$key) && $beforeData->$key != $value) { $changedFields[] = $key; } } // Run specific logic based on field changes $shouldRunSpoolStatusChanger = !empty(array_intersect($changedFields, $spoolRelatedFields)); ``` ### 4. Complex Business Logic Triggers can implement sophisticated business rules: - **Data Synchronization**: Keep related tables in sync - **Status Updates**: Update status fields based on conditions - **Calculations**: Perform complex calculations and updates - **Validation**: Ensure data integrity across tables ## Performance Optimizations ### Database Locking Prevention The system uses chunking and transaction management to prevent database locking issues: ```php // Example: Processing large datasets in chunks $recordsChunked = $records->chunk(5); // Process 5 records at a time foreach($recordsChunked as $chunk) { DB::transaction(function () use ($chunk) { foreach($chunk as $record) { // Update logic here } }, 3); // Retry up to 3 times usleep(100000); // 0.1 second pause between chunks } ``` ### Memory Management - Small chunk sizes (3-10 records per chunk) - Short transaction durations - Automatic retry mechanisms - Memory limit configurations ## Example Trigger Implementations ### Simple Upsert Trigger ```php where("id", $request['key'])->first(); $uniqueFields = [ 'line_number' => $data->line, 'support_code' => $data->component_code_id, ]; $dataToUpdate = [ 'zone' => $data->project, 'line_number' => $data->line, 'rev' => $data->rev, 'support_code' => $data->component_code_id, 'erection_materials_name' => $data->description_ru, 'standart' => $data->manufacturing_standard, 'materials' => $data->material, 'quantity' => $data->quantity, 'welded_pad_measure' => $data->odmm_1, 'thickness' => $data->thicknessmm_1, 'unit_weight' => $data->weight, 'total_weight' => $data->total_weight, 'designer' => $data->designer, ]; echo db('supports')->updateOrInsert($uniqueFields, $dataToUpdate); ?> ``` ### Complex Multi-Table Trigger ```php where("id", $id)->first(); // Detect field changes $changedFields = []; $dataArray = (array) $data; foreach ($dataArray as $key => $value) { if (isset($beforeData->$key) && $beforeData->$key != $value) { $changedFields[] = $key; } } // Define field groups for different operations $spoolRelatedFields = ['spool_number', 'iso_number', 'type_of_joint']; $ndeRelatedFields = ['type_of_welds', 'fluid_code', 'type_of_joint']; // Determine which operations to run $shouldRunSpoolStatusChanger = !empty(array_intersect($changedFields, $spoolRelatedFields)); $shouldRunNdeMatrixUpdate = !empty(array_intersect($changedFields, $ndeRelatedFields)); // Execute specific operations based on changes if ($shouldRunSpoolStatusChanger) { // Update spool status $spoolStatusChangerParams = [ 'spool_number' => $data->spool_number, 'iso_number' => $data->iso_number, ]; $spoolStatusChangerView = view('cron.spool-status-changer', $spoolStatusChangerParams)->render(); } if ($shouldRunNdeMatrixUpdate) { // Update NDE matrix // Complex NDE logic here } ?> ``` ## Supervisor System ### What is Supervisor? Supervisor is a process control system that ensures your queue workers keep running. Think of it as a manager that: - **Starts** queue workers when the server boots - **Monitors** them continuously - **Restarts** them if they crash - **Logs** their activities ### Supervisor Configuration ```ini [program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /path/to/your/project/artisan queue:work --sleep=3 --tries=3 --max-time=3600 autostart=true autorestart=true stopasgroup=true killasgroup=true user=www-data numprocs=8 redirect_stderr=true stdout_logfile=/path/to/your/project/storage/logs/worker.log stopwaitsecs=3600 ``` ### Why Use Supervisor? 1. **Reliability**: Workers automatically restart if they crash 2. **Scalability**: Can run multiple workers simultaneously 3. **Monitoring**: Easy to monitor worker status 4. **Logging**: All worker activities are logged ### Supervisor Commands ```bash # Check supervisor status sudo supervisorctl status # Restart all workers sudo supervisorctl restart laravel-worker:* # Restart specific worker sudo supervisorctl restart laravel-worker:laravel-worker_00 # Reload supervisor configuration sudo supervisorctl reread sudo supervisorctl update ``` ## Telescope Job Monitoring ### What is Telescope? Laravel Telescope is a debugging and monitoring tool that provides insight into your application's requests, exceptions, logs, database queries, cache operations, job executions, and more. ### Job Tracking with Tags The Save Trigger system uses custom tags to make job tracking easier in Telescope: ```php public function tags(): array { $action = $this->key ? 'Update' : 'Create'; return [ "SaveTrigger:{$this->tableName}", "Action:{$action}", "Table:{$this->tableName}" ]; } ``` ### How to Monitor Jobs in Telescope 1. **Access Telescope**: Go to `/telescope` in your application 2. **Navigate to Jobs**: Click on "Jobs" in the sidebar 3. **Filter by Tags**: Use the search/filter to find specific jobs: - `SaveTrigger:weld_logs` - All weld log triggers - `Action:Update` - All update operations - `Table:test_packages` - All test package triggers ### Telescope Job Details Each job in Telescope shows: ``` Job Details: β”œβ”€β”€ Description: "Execute Save Trigger for weld_logs table - Update operation" β”œβ”€β”€ Tags: ["SaveTrigger:weld_logs", "Action:Update", "Table:weld_logs"] β”œβ”€β”€ Queue: "default" β”œβ”€β”€ Status: "processed" β”œβ”€β”€ Execution Time: "2.5s" β”œβ”€β”€ Memory Usage: "45.2MB" └── Exception: (if any) ``` ### Advanced Telescope Filtering ```php // In Telescope configuration 'watchers' => [ Watchers\JobWatcher::class => [ 'enabled' => env('TELESCOPE_JOB_WATCHER', true), 'ignore' => [ // Ignore specific jobs if needed ], ], ], ``` ### Job Performance Monitoring Monitor job performance patterns: 1. **Execution Time**: Track how long jobs take to complete 2. **Memory Usage**: Monitor memory consumption 3. **Failure Rate**: Check job failure patterns 4. **Queue Depth**: Monitor queue backlog ### Telescope Dashboard Create custom Telescope dashboards to monitor: - **Job Success Rate**: Percentage of successful jobs - **Average Execution Time**: Mean job duration - **Queue Depth**: Number of pending jobs - **Error Patterns**: Common job failures ## Best Practices ### 1. Error Handling Always include proper error handling in trigger files: ```php try { // Trigger logic here echo db('target_table')->updateOrInsert($uniqueFields, $dataToUpdate); } catch (\Exception $e) { Log::error("Save trigger error for {$tableName}: " . $e->getMessage()); // Don't throw - let the job fail gracefully } ``` ### 2. Performance Optimization - Use database indexes on frequently queried fields - Implement change detection to avoid unnecessary operations - Use batch operations when possible - Set appropriate database timeouts ### 3. Monitoring - Use Telescope to monitor job execution - Implement logging for debugging - Set up job failure notifications ### 4. Testing - Test triggers with various data scenarios - Verify data consistency after trigger execution - Monitor performance impact ## Configuration ### Queue Configuration Ensure your queue is properly configured in `config/queue.php`: ```php 'default' => env('QUEUE_CONNECTION', 'database'), ``` ### Job Timeout Set appropriate timeout values for long-running triggers: ```php // In trigger files DB::statement('SET SESSION innodb_lock_wait_timeout = 300'); DB::statement('SET SESSION lock_wait_timeout = 300'); ini_set('memory_limit', '512M'); ini_set('max_execution_time', 600); ``` ## Troubleshooting ### Common Issues 1. **Job Not Executing**: Check queue worker is running 2. **Data Not Syncing**: Verify trigger file exists and has correct logic 3. **Performance Issues**: Implement change detection and optimize queries 4. **Memory Issues**: Increase memory limits and optimize data processing ### Debugging 1. Check Telescope for job details and execution logs 2. Review Laravel logs for error messages 3. Test trigger files independently 4. Monitor database performance during trigger execution ## Security Considerations 1. **Input Validation**: Always validate data in trigger files 2. **SQL Injection**: Use Laravel's query builder methods 3. **Access Control**: Ensure proper authentication and authorization 4. **Data Integrity**: Implement proper error handling and rollback mechanisms This Save Trigger System provides a robust, scalable solution for maintaining data consistency and implementing complex business rules across the application.