Files
citrus-cms/resources/views/guide/save-trigger-system-guide.md
T
2026-04-28 21:15:09 +03:00

18 KiB

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:

// 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:

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
// 1. Get the updated record
$data = db($tableName)->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:

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:

// 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:

// 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
// m_t_o_s.php - Material Take Off Sheet trigger
$data = db("m_t_o_s")->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
// weld_logs.php - Complex welding log trigger
$id = $request['key'];
$data = db($tableName)->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

[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

# 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:

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

// 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:

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:

'default' => env('QUEUE_CONNECTION', 'database'),

Job Timeout

Set appropriate timeout values for long-running triggers:

// 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.