our-edu / laravel-sqs-messaging
Laravel package for AWS SQS messaging with RabbitMQ rollback support
Installs: 80
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 1
pkg:composer/our-edu/laravel-sqs-messaging
Requires
- php: ^8.1
- aws/aws-sdk-php: ^3.0
- illuminate/console: ^9.0|^10.0
- illuminate/database: ^9.0|^10.0
- illuminate/support: ^9.0|^10.0
- predis/predis: ^1.1
Requires (Dev)
- orchestra/testbench: ^7.0|^8.0
- phpunit/phpunit: ^9.0|^10.0
This package is auto-updated.
Last update: 2026-01-15 11:18:15 UTC
README
A comprehensive Laravel package for AWS SQS messaging with RabbitMQ rollback support, idempotency, error handling, and CloudWatch metrics integration.
Features
- ✅ AWS SQS integration with automatic queue/DLQ creation
- ✅ Message envelope with idempotency keys
- ✅ Redis + Database idempotency checking
- ✅ Error classification (validation, transient, permanent)
- ✅ CloudWatch metrics integration
- ✅ Dead Letter Queue (DLQ) management
- ✅ Long polling support
- ✅ RabbitMQ adapter for easy migration
- ✅ Environment-aware queue naming
Installation
Via Composer
composer require our-edu/laravel-sqs-messaging:1.*
Via VCS Repository (For Development)
Add to your composer.json:
{
"repositories": {
"laravel-sqs-messaging": {
"type": "vcs",
"url": "https://github.com/our-edu/laravel-sqs-messaging"
}
},
"require": {
"our-edu/laravel-sqs-messaging": "1.*"
}
}
Then run:
composer require our-edu/laravel-sqs-messaging:1.*
Configuration
1. Publish Configuration
php artisan vendor:publish --provider="OurEdu\SqsMessaging\SqsMessagingServiceProvider"
2. Environment Variables
Add to your .env:
# AWS Credentials (required) AWS_SQS_ACCESS_KEY_ID=your-access-key AWS_SQS_SECRET_ACCESS_KEY=your-secret-key AWS_DEFAULT_REGION=me-central-1 # SQS Configuration SQS_QUEUE_PREFIX=staging # or production, dev, etc. # Messaging Driver MESSAGING_DRIVER=sqs # Use SQS (default) or rabbitmq for rollback MESSAGING_FALLBACK_TO_RABBITMQ=true # Enable fallback to RabbitMQ when SQS queue doesn't exist # CloudWatch Metrics (optional) SQS_CLOUDWATCH_ENABLED=true SQS_CLOUDWATCH_NAMESPACE=SQS/PaymentService
Note: Set MESSAGING_FALLBACK_TO_RABBITMQ=true if you have other projects still using RabbitMQ. This ensures messages go to RabbitMQ when SQS queue doesn't exist.
3. Configure Queues
Edit config/sqs_queues.php:
return [ 'payment' => [ 'default' => 'payment-service-queue', 'specific' => [ 'refunds' => 'payment-service-refunds-queue', ], ], ];
4. Configure Event Mappings
Edit config/sqs_events.php:
return [ 'StudentEnrolled' => \App\Events\StudentEnrolled::class, 'StudentWithdraw' => \App\Events\StudentWithdraw::class, ];
5. Run Migration
php artisan migrate
This creates the processed_events table for idempotency.
6. Ensure Queues Exist
php artisan sqs:ensure
For Production: Add this to your entrypoint.sh or container startup script to ensure queues exist before starting consumers:
php artisan sqs:ensure || echo "Warning: SQS queue ensure failed, but continuing startup..."
Usage
Publishing Messages
Option 1: Use Unified MessagingService (Recommended)
The package includes a MessagingService that can switch between available drivers (SQS and RabbitMQ).
Step 1: Update your Support\RabbitMQ\Publishable trait and add the following method:
public static function publishFromInstance(object $event): void { Container::getInstance() ->make(Publisher::class) ->publish($event); }
Complete updated trait:
<?php declare(strict_types=1); namespace Support\RabbitMQ; use Illuminate\Container\Container; use Illuminate\Contracts\Container\BindingResolutionException; trait Publishable { /** * @return void * @throws BindingResolutionException */ public static function publish(): void { Container::getInstance() ->make(Publisher::class) ->publish(new static(...func_get_args())); } public static function publishFromInstance(object $event): void { Container::getInstance() ->make(Publisher::class) ->publish($event); } }
Step 2: In your listeners where you publish a message, replace RabbitMQ publishing code:
Old RabbitMQ Publisher:
Notification::publish($queueName, $payload)
New MessagingService Publisher:
app(MessagingService::class)->publish( event: new Notification($queueName, $payload), eventClassReference: Notification::class );
Example Migration:
Old RabbitMQ Listener:
namespace Domain\Payments\Listeners\ReversePaymentRequest; use App\BaseApp\Enums\RoleEnum; use Domain\Models\User; use Domain\Payments\Events\ReversePaymentRequest\ReversePaymentRequestCreatedEvent; use Domain\Payments\Notifications\ReversePaymentRequestNotification; use Illuminate\Contracts\Container\BindingResolutionException; class ReversePaymentRequestCreatedListener { /** * @throws BindingResolutionException */ public function handle(ReversePaymentRequestCreatedEvent $event): void { $users = User::query()->whereHas('roles', function ($query) { $query->whereIn('name', [RoleEnum::ACCOUNTANT_MANAGER, RoleEnum::ACCOUNTANT_MANAGER]); })->get(); $usersUuids = $users->pluck('uuid')->toArray(); ReversePaymentRequestNotification::publish($event->reversePaymentRequest, $usersUuids); } }
New Listener using MessagingService:
namespace Domain\Payments\Listeners\ReversePaymentRequest; use App\BaseApp\Enums\RoleEnum; use Domain\Models\User; use Domain\Payments\Events\ReversePaymentRequest\ReversePaymentRequestCreatedEvent; use Domain\Payments\Notifications\ReversePaymentRequestNotification; use Illuminate\Contracts\Container\BindingResolutionException; use OurEdu\SqsMessaging\MessagingService; class ReversePaymentRequestCreatedListener { /** * @throws BindingResolutionException */ public function handle(ReversePaymentRequestCreatedEvent $event): void { $users = User::query()->whereHas('roles', function ($query) { $query->whereIn('name', [RoleEnum::ACCOUNTANT_MANAGER, RoleEnum::ACCOUNTANT_MANAGER]); })->get(); $usersUuids = $users->pluck('uuid')->toArray(); // New messaging service publish app(MessagingService::class)->publish( event: new ReversePaymentRequestNotification(queueName: $this->queueName, payload: $event->students), eventClassReference: ReversePaymentRequestNotification::class ); } }
Switch drivers via environment variable:
MESSAGING_DRIVER=sqs # Use SQS (default) MESSAGING_DRIVER=rabbitmq # Rollback to RabbitMQ
Option 2: Direct SQS Adapter
HINT: This approach will publish directly to SQS (bypasses driver switching):
use App\Events\StudentEnrolled; use OurEdu\SqsMessaging\Drivers\Sqs\SQSPublisherAdapter; $adapter = app(SQSPublisherAdapter::class); $adapter->publish(new StudentEnrolled($student), 'payment-service-queue');
Consuming Messages
Add to Supervisor configuration:
[program:sqs-payment-consumer] command=php /var/www/artisan sqs:consume payment-service-queue autostart=true autorestart=true user=www-data numprocs=2 stdout_logfile=/var/www/storage/logs/payment-consumer.log
Available Commands
# Ensure all queues exist php artisan sqs:ensure # Consume messages from a queue php artisan sqs:consume {queue} # Test AWS connection php artisan sqs:test:connection # Inspect DLQ messages php artisan sqs:inspect-dlq {queue} # Monitor DLQ depth php artisan sqs:monitor-dlq # Replay DLQ messages php artisan sqs:replay-dlq {queue} --limit=10 # Cleanup old processed events php artisan sqs:cleanup-processed-events --days=7
Rollback & Cleanup
See ROLLBACK_GUIDE.md for detailed instructions on:
- Rolling back from SQS to RabbitMQ
- Cleaning up RabbitMQ code once SQS is stable
- Dual write mode for gradual migration
Production Deployment
Ensure Queues Before Startup
Add to your production entrypoint.sh or container startup script:
php artisan sqs:ensure || echo "Warning: SQS queue ensure failed, but continuing startup..."
This ensures all required SQS queues and DLQs exist before starting consumers or the application.
Production Environment Variables
# AWS Authentication (REQUIRED) AWS_SQS_ACCESS_KEY_ID=your-production-access-key AWS_SQS_SECRET_ACCESS_KEY=your-production-secret-key AWS_DEFAULT_REGION=us-east-2 # Production Settings SQS_QUEUE_PREFIX=production SQS_AUTO_ENSURE=false # Disable auto-creation in production SQS_CLOUDWATCH_ENABLED=true # Enable monitoring MESSAGING_DRIVER=sqs # Use SQS MESSAGING_DUAL_WRITE=false # Disable dual write MESSAGING_FALLBACK_TO_RABBITMQ=true # Enable fallback to resolve other projects that work with rabbitmq
For detailed production deployment guide, see DEPLOYMENT.md.
Requirements
- PHP ^8.1
- Laravel ^9.0|^10.0
- AWS SDK PHP ^3.0
- Redis (for idempotency)
- AWS SQS access
License
MIT
Support
For issues and questions, please contact the OurEdu development team.