One-Time Operations for Laravel

repository·main·Indexed 20 days ago

https://github.com/timokoerber/laravel-one-time-operations

A Laravel package for running specific tasks, such as data seeding or updates, exactly once after a deployment. It provides a migration-like system for post-deployment jobs, featuring asynchronous or synchronous execution, tagging, and tracking via a database table. Includes Artisan commands for creating operations (operations:make), processing them (operations:process), and viewing their status (operations:show).

Tokens
4.5K
Snippets
21
Records
22
Agent score
69%

What's inside laravel-one-time-operations

  1. Integrate One-Time Operations into CI/CD

    main

    To automate operations, include php artisan operations:process in your deployment script immediately after your migrations. This ensures data updates or seeding happen automatically after code deployment.

    Example deployment sequence:

    # ... deployment steps ...
    php artisan migrate
    php artisan operations:process
    ...
     - php artisan migrate
     - php artisan operations:process
    ...
  2. Configure One-Time Operations settings

    main

    By default, the package uses a database table named operations and a directory named operations in your project root. To customize these, publish the configuration file:

    php artisan vendor:publish --provider="TimoKoerber\\LaravelOneTimeOperations\\Providers\\OneTimeOperationsServiceProvider"

    Then, edit config/one-time-operations.php:

    return [
        'directory' => 'operations',
        'table' => 'operations',
    ];
    // config/one-time-operation.php
    
    return [
        'directory' => 'operations',
        'table' => 'operations',
    ];
  3. Implement a One-Time Operation class

    main

    Operation files are anonymous classes extending OneTimeOperation. You must implement the logic inside the process() method.

    By default, operations are processed asynchronously using the default queue. You can control this behavior using the following protected properties:

    • bool $async: Set to false to force synchronous execution (recommended only for very small operations).
    • string $queue: The name of the queue to dispatch the job to (ignored if $async is false).
    • ?string $tag: A tag used to filter operations during processing.

    Example implementation:

    use TimoKoerber\
    LaravelOneTimeOperations\\OneTimeOperation;
    
    return new class extends OneTimeOperation
    {
        protected bool $async = true;
        protected string $queue = 'default';
        protected ?string $tag = 'my-tag';
    
        public function process(): void
        {
            // Your logic here
            User::where('active', 1)->update(['status' => 'awesome']);
        }
    };
    <?php
    
    use TimoKoerber\LaravelOneTimeOperations\OneTimeOperation;
    
    return new class extends OneTimeOperation
    {
        /**
         * Determine if the operation is being processed asynchronously.
         */
        protected bool $async = true;
        
        /**
         * The queue that the job will be dispatched to.
         */
        protected string $queue = 'default';
        
        /**
         * A tag name, that this operation can be filtered by.
         */
        protected ?string $tag = null;
    
        /**
         * Process the operation.
         */
        public function process(): void
        {
            //
        }
    };
  4. Configure the operations directory and database table

    main

    The manager relies on the one-time-operations configuration keys to locate files and identify the database table used for tracking.

    • one-time-operations.directory: The directory name (relative to the Laravel application base path) where operation files are stored.
    • one-time-operations.table: The name of the database table used to track processed operations. Defaults to operations if not specified.
  5. Process One-Time Operations

    main

    Run the operations:process command to execute pending operations. This command can be customized with several flags:

    • --sync: Force synchronous execution (ignores the $async property).
    • --async: Force asynchronous execution (ignores the $async property).
    • --test: Run operations in test mode (they will not be flagged as processed in the database).
    • --isolated: Run the command as an isolated instance (useful for multi-server architectures).
    • --queue=<name>: Force all operations to run on a specific queue (overrides the $queue property).
    • --tag=<tagname>: Only process operations that match the specified tag. You can provide multiple tags by repeating the flag.

    To re-run a specific operation, provide its name as an argument.

    # Process all pending operations
    php artisan operations:process
    
    # Process only operations with a specific tag
    php artisan operations:process --tag=awesome
    
    # Re-run a specific operation by name
    php artisan operations:process XXXX_XX_XX_XXXXXX_awesome_operation
    php artisan operations:process
  6. Show the status of operations

    main

    Use the operations:show command to view the status of your operations. You can filter the output using the following keywords:

    • pending: Operations that have not been processed yet.
    • processed: Operations that have been successfully executed.
    • disposed: Operations that have been processed and whose files have been deleted from the repository.
    # Show all operations
    php artisan operations:show
    
    # Show only pending operations
    php artisan operations:show pending
    
    # Show pending and disposed operations
    php artisan operations:show pending disposed
    php artisan operations:show
  7. Create a new One-Time Operation file

    main

    Use the operations:make command (or its alias make:operation) to generate a new operation class. You can use the --essential or -e flag to create a minimal file without extra attributes.

    # Standard operation
    php artisan operations:make AwesomeOperation
    
    # Minimal operation
    php artisan operations:make AwesomeOperation --essential
    php artisan operations:make AwesomeOperation
  8. Interact with operation files via OneTimeOperationFile

    main

    The OneTimeOperationFile class is used to represent and inspect an operation file on disk. It provides methods to extract the operation's name, retrieve the underlying class object, and check if the operation has already been recorded in the database.

    Key Methods

    • make(SplFileInfo $file): A static factory method to instantiate a new instance.
    • getOperationName(): Returns the name of the operation by removing the .php extension from the filename.
    • getClassObject(): Loads and returns the actual OneTimeOperation class instance from the file using File::getRequire().
    • getModel(): Queries the database to find an existing Operation model matching the operation's name. Returns null if no record exists.
    use TimoKoerber//LaravelOneTimeOperations
    use Symfony//Component/Finder/SplFileInfo;
    
    $fileInfo = new SplFileInfo('/path/to/operations/my_custom_operation.php');
    $operationFile = OneTimeOperationFile::make($fileInfo);
    
    $name = $operationFile->getOperationName(); // 'my_custom_operation'
    $class = $operationFile->getClassObject(); // The instance of the operation class
    $model = $operationFile->getModel();      // The Operation model from the DB, if it exists
  9. Get an operation file by name

    main

    If you know the name of an operation, you can retrieve its corresponding OneTimeOperationFile object. The manager resolves the name to a file path by appending .php and looking in the configured operations directory.

    • getOperationFileByName(string $operationName): Returns a OneTimeOperationFile. Throws a FileNotFoundException if the file does not exist.
    • fileExistsByName(string $operationName): Returns a boolean indicating if the operation file exists.
    use TimoKoerber\LaravelOneTimeOperations\OneTimeOperationManager;
    
    if (OneTimeOperationManager::fileExistsByName('migrate_users_to_new_table')) {
        $operationFile = OneTimeOperationManager::getOperationFileByName('migrate_users_to_new_table');
    }
  10. Store a one-time operation using Operation::storeOperation()

    main

    You can programmatically record a one-time operation in the database using the storeOperation static method. This method ensures that an operation is only created if it doesn't already exist (idempotency).

    Parameters:

    • string $operation: The unique name of the operation.
    • bool $async: Whether the operation should be marked as async or sync.
    use TimoKoerber\LaravelOneTimeOperations\Models\Operation;
    
    // Store an operation as synchronous
    Operation::storeOperation('my-unique-task', false);
    
    // Store an operation as asynchronous
    Operation::storeOperation('another-task', true);