承接 bugfix666/laravel-outbox 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

bugfix666/laravel-outbox

Composer 安装命令:

composer require bugfix666/laravel-outbox

包简介

Transactional Outbox pattern for Laravel

README 文档

README

Latest Version on Packagist PHP Version Laravel Version License PHP Run Tests Total Downloads

Transactional Outbox pattern implementation for Laravel 12+ (PHP 8.4+).
Guarantees atomicity and reliable event delivery in distributed systems, especially fintech, e‑commerce, and microservices.

📊 Comparison with Existing Solutions

There are several open‑source implementations of the Transactional Outbox pattern for Laravel. Here’s how laravel-outbox compares to them:

Feature This Package webrek/laravel-outbox GaiPalyan/laravel-outbox Dnakitare/laravel-outbox
PHP Version 8.4+ 8.1+ 8.1+ 8.2+
Laravel Version 12+ 10+ 10+ 10 – 12
PHP 8.4 Features (typed properties, readonly, attributes) ✅ Full
Production‑ready ✅ Yes ✅ Yes ✅ Yes ⚠️ Beta (0.1.0-beta1)
Strict Typing ✅ Yes
Unit & Feature Tests ✅ 15 tests ✅ (limited)
Dead Letter Queue (DLQ) ✅ Yes ✅ Yes
Inbox Pattern ❌ (outbox only)
Event / Job Interception ❌ (explicit control) ✅ (auto‑intercepts)
Atomicity ✅ (single DB transaction)
Custom Publishers ✅ (via contract)
Retry Logic ✅ (exponential backoff)
Worker Locking ✅ (prevents parallel runs)
Cleanup Command ✅ (outbox:cleanup)
Monitoring Events ✅ (Processed / Failed)

🚀 Why This Package Stands Out

  1. Cutting‑Edge Stack – Built specifically for PHP 8.4+ and Laravel 12+, leveraging the latest language features for cleaner, safer, and more maintainable code.

  2. Production‑Ready – Unlike some alternatives that are still in beta, this package is fully tested (15+ unit and feature tests) and ready for mission‑critical applications.

  3. Dead Letter Queue (DLQ) – Failed messages after all retries are not lost. They remain in the outbox table for inspection and manual intervention – essential for fintech and reliability‑first systems.

  4. Explicit Control, No Magic – Unlike packages that automatically intercept all events/jobs, this package gives you full control over what and when to publish. No surprises, easier debugging, and predictable behavior.

  5. Built‑in Monitoring – The OutboxMessageProcessed and OutboxMessageFailed events allow seamless integration with logging, metrics (Prometheus, StatsD), and alerting.

  6. Strict Typing & Modern Practices – Readonly classes, typed properties, constructor property promotion, and console command attributes make the code self‑documenting and robust.

If you need a reliable, modern, and transparent outbox implementation for your fintech or distributed system – this package is the best choice among all existing open‑source solutions.

📦 Features

  • Atomic persistence – business data + outbox record in a single DB transaction.
  • Reliable background processing – worker with locking, batch processing, and retries.
  • Flexible publishers – log, queue, or your own (Kafka, RabbitMQ, SNS, etc.).
  • Built‑in retry logic – exponential backoff (configurable attempts & delay).
  • Monitoring – events for processed/failed messages; easy to integrate with logging or metrics.
  • Cleanup – automated purging of old processed messages.
  • Modern PHP 8.4+ – typed properties, readonly classes, enums, constructor promotion.
  • Laravel 12+ ready – uses new attribute‑based console commands.

🔧 Requirements

  • PHP 8.4 or higher
  • Laravel 12.0 or higher
  • Database that supports transactions (MySQL, PostgreSQL, SQLite, etc.)

📥 Installation

composer require bugfix666/laravel-outbox

🚀 Setup

Publish the configuration and migration files:

php artisan vendor:publish --tag=outbox-config
php artisan vendor:publish --tag=outbox-migrations

Run the migration to create the outbox_messages table:

php artisan migrate

⚙️ Configuration

The config file config/outbox.php allows you to tailor the package to your needs:

return [
    'table'      => env('OUTBOX_TABLE', 'outbox_messages'),
    'connection' => env('OUTBOX_DB_CONNECTION', env('DB_CONNECTION', 'mysql')),

    // Your custom publisher class (must implement OutboxPublisher)
    'publisher'  => env('OUTBOX_PUBLISHER', Bugfix666\LaravelOutbox\Publishers\LogPublisher::class),

    'worker' => [
        'batch_size'   => env('OUTBOX_BATCH_SIZE', 100),
        'lock_timeout' => env('OUTBOX_LOCK_TIMEOUT', 10), // seconds
        'lock_store'   => env('OUTBOX_LOCK_STORE', 'cache'), // cache, redis, etc.
    ],

    'cleanup' => [
        'days' => env('OUTBOX_CLEANUP_DAYS', 7),
    ],

    'retry' => [
        'max_attempts'   => env('OUTBOX_MAX_ATTEMPTS', 5),
        'delay_seconds'  => env('OUTBOX_RETRY_DELAY', 60), // seconds between attempts
    ],
];

Set your preferred publisher in .env:

OUTBOX_PUBLISHER=App\Publishers\KafkaPublisher
OUTBOX_BATCH_SIZE=50
OUTBOX_MAX_ATTEMPTS=3

💡 Basic Usage

1. Store an outbox message inside a transaction

use Bugfix666\LaravelOutbox\Services\OutboxService;
use Illuminate\Support\Facades\DB;

DB::transaction(function () use ($outboxService) {
    // 1. Business logic (e.g., create a payment)
    $payment = Payment::create([
        'amount' => 1000,
        'currency' => 'USD',
        'status' => 'completed',
    ]);

    // 2. Store the outbox message – guaranteed to be persisted atomically
    $outboxService->store(
        aggregateType: 'Payment',
        aggregateId: (string) $payment->id,
        eventType: 'payment.completed',
        payload: [
            'payment_id' => $payment->id,
            'amount' => $payment->amount,
            'user_id' => auth()->id(),
        ]
    );
});

2. Run the worker

Start the outbox processor (should be supervised in production):

php artisan outbox:process

You can override batch size on the fly:

php artisan outbox:process --batch-size=200

3. Clean up old processed messages

Schedule the cleanup command to run daily (in routes/console.php):

use Illuminate\Support\Facades\Schedule;

Schedule::command('outbox:cleanup')->daily();

Or run manually:

php artisan outbox:cleanup --days=14

🔌 Custom Publisher

By default, the package logs events. To send events to a real broker, create a class that implements Bugfix666\LaravelOutbox\Contracts\OutboxPublisher:

namespace App\Publishers;

use Bugfix666\LaravelOutbox\Contracts\OutboxPublisher;
use RdKafka\Producer;

class KafkaPublisher implements OutboxPublisher
{
    public function __construct(private Producer $producer) {}

    public function publish(string $eventType, array $payload, ?string $aggregateId = null): bool
    {
        $topic = $this->producer->newTopic($eventType);
        $topic->produce(RD_KAFKA_PARTITION_UA, 0, json_encode($payload));
        $this->producer->flush(1000);
        return true;
    }
}

Then set OUTBOX_PUBLISHER=App\Publishers\KafkaPublisher in your .env.

Tip: For RabbitMQ, use php-amqplib; for AWS SNS, use the Laravel SNS facade.

🧩 Monitoring and Events

The package fires two events that you can listen to:

  • Bugfix666\LaravelOutbox\Events\OutboxMessageProcessed
  • Bugfix666\LaravelOutbox\Events\OutboxMessageFailed

Example listener:

use Bugfix666\LaravelOutbox\Events\OutboxMessageFailed;

class LogOutboxFailure
{
    public function handle(OutboxMessageFailed $event): void
    {
        logger()->error('Outbox failure', [
            'id' => $event->message->id,
            'attempts' => $event->message->attempts,
            'error' => $event->exception->getMessage(),
        ]);
    }
}

Register your listener in EventServiceProvider.

🔄 Retry Logic

When publishing fails, the worker increments the attempts counter and sets available_at to now() + delay_seconds. The next run will only pick messages where available_at is in the past, giving the broker time to recover.

After max_attempts failures, the message remains unprocessed but is considered failed – you can handle it manually or set up an alert.

🧪 Testing

The package is fully testable. You can mock the publisher and assert that messages are stored and processed correctly.

Example test:

public function test_message_is_stored(): void
{
    DB::transaction(function () {
        $service = app(OutboxService::class);
        $message = $service->store('User', '123', 'user.created', ['name' => 'John']);
        $this->assertDatabaseHas('outbox_messages', ['id' => $message->id]);
    });
}

📊 Performance Considerations

  • Indexes – The migration includes indexes on (processed_at, created_at), aggregate_type/aggregate_id, and available_at to keep queries fast.
  • Batch size – Tune batch_size according to your workload. Larger batches reduce DB round‑trips but increase memory usage.
  • Partitioning – For extremely high volume, consider table partitioning by created_at (e.g., daily) to keep the active set small.
  • Locking – The worker uses FOR UPDATE to prevent double‑processing. Ensure your database supports row‑level locking.

🛠 Supervisor Configuration

For production, keep the worker running with Supervisor:

[program:outbox-worker]
command=php /path/to/your/project/artisan outbox:process
directory=/path/to/your/project
user=www-data
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/path/to/your/project/storage/logs/outbox-worker.log

📖 Full Documentation

🤝 Contributing

  1. Fork the repository.
  2. Create a feature branch (git checkout -b feature/amazing-feature).
  3. Commit your changes (git commit -m 'Add some amazing feature').
  4. Push to the branch (git push origin feature/amazing-feature).
  5. Open a Pull Request.

Please ensure that your code passes the existing tests and is well‑documented.

📝 License

This package is open‑source software licensed under the MIT license.

💬 Support

For questions, bug reports, or feature requests, please open an issue on GitHub.

Happy coding, and may your events always be delivered! 🚀

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: GPL-3.0-only
  • 更新时间: 2026-06-22

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固