diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index f7492c5..94f2b3a 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: true matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest] php: [8.3, 8.2, 8.1] laravel: [10.*] stability: [prefer-lowest, prefer-stable] diff --git a/README.md b/README.md index fc43f96..104f132 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,36 @@ # This is my package azure-queue-laravel -[![Latest Version on Packagist](https://img.shields.io/packagist/v/milo/azure-queue-laravel.svg?style=flat-square)](https://packagist.org/packages/milo/azure-queue-laravel) -[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/milo/azure-queue-laravel/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/milo/azure-queue-laravel/actions?query=workflow%3Arun-tests+branch%3Amain) -[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/milo/azure-queue-laravel/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/milo/azure-queue-laravel/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) -[![Total Downloads](https://img.shields.io/packagist/dt/milo/azure-queue-laravel.svg?style=flat-square)](https://packagist.org/packages/milo/azure-queue-laravel) +[![Latest Version on Packagist](https://img.shields.io/packagist/v/digitalclaim/azure-queue-laravel.svg?style=flat-square)](https://packagist.org/packages/digitalclaim/azure-queue-laravel) +[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/digitalclaim/azure-queue-laravel/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/digitalclaim/azure-queue-laravel/actions?query=workflow%3Arun-tests+branch%3Amain) +[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/digitalclaim/azure-queue-laravel/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/digitalclaim/azure-queue-laravel/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) +[![Total Downloads](https://img.shields.io/packagist/dt/digitalclaim/azure-queue-laravel.svg?style=flat-square)](https://packagist.org/packages/milo/azure-queue-laravel) -This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. +Azure Storage Queue for Laravel. This works fundamentally different than the normal Laravel queue worker. We will push items to the storage queue as usual, but instead of constant pulling with something like `queue:liste` we use Azure Storage Queue trigger to call a Azure Function. The Azure Function will then call our Laravel app with the job payload to process it. There is no need to run a `queue:work/listen` command. -## Support us +This package is inspired by [stackkit/laravel-google-cloud-tasks-queue](https://github.com/stackkit/laravel-google-cloud-tasks-queue) and based on [squigg/azure-queue-laravel](https://github.com/squigg/azure-queue-laravel). -[](https://spatie.be/github-ad-click/azure-queue-laravel) +Warning: Currently we do not save failed jobs in any way. However, it's possible to use Laravel queue callbacks to do so. -We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). - -We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). +```php +public function boot(): void +{ + Queue::before(function (JobProcessing $event) { + // before processing + }); + + Queue::after(function (JobProcessed $event) { + // after processing + }); + + Queue::exceptionOccurred(function (JobExceptionOccurred $event) { + // on error (for each retry) + }); + + Queue::failing(function (JobFailed $event) { + // on fail (after all retries) + }); +} +``` ## Installation @@ -33,14 +50,73 @@ This is the contents of the published config file: ```php return [ + 'worker' => [ + 'backoff' => env('DIGITALCLAIM_AZURE_QUEUE_LARAVEL_BACKOFF', 60 * 5), // backoff time in seconds + 'maxTries' => env('DIGITALCLAIM_AZURE_QUEUE_LARAVEL_MAXTRIES', 3), // max number of retries + ], ]; ``` ## Usage +1. You already have setup your Azure App Service and Storage Account +2. Add new queue connection in `config/queue.php` + ```php -$azureQueue = new DigitalClaim\AzureQueue(); -echo $azureQueue->echoPhrase('Hello, digitalclaim!'); +'azure' => [ + 'driver' => 'azurepush', // Leave this as-is + 'protocol' => 'https', // https or http + 'accountname' => env('AZURE_QUEUE_STORAGE_NAME'), // Azure storage account name + 'key' => env('AZURE_QUEUE_KEY'), // Access key for storage account + 'queue' => env('AZURE_QUEUE_NAME'), // Queue container name + 'timeout' => 60, // Seconds before a job is released back to the queue + 'endpoint' => env('AZURE_QUEUE_ENDPOINTSUFFIX'), // Optional endpoint suffix if different from core.windows.net + 'queue_endpoint' => env('AZURE_QUEUE_ENDPOINT'), // Optional endpoint for custom addresses like http://localhost/my_storage_name +], +``` + +3. Set environment variables + +```bash +QUEUE_CONNECTION=azure + +AZURE_QUEUE_STORAGE_NAME=YOUR_QUEUE_STORAGE_NAME +AZURE_QUEUE_KEY=YOUR_QUEUE_KEY +AZURE_QUEUE_NAME=YOUR_QUEUE_NAME +#AZURE_QUEUE_ENDPOINTSUFFIX=core.windows.net +#AZURE_QUEUE_ENDPOINT=https +``` + +4. Trigger Azure Function App (nodejs) for new queue items (see https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue-trigger) + +```javascript +const axios = require("axios"); + +module.exports = async function (context, myQueueItem, more) { + try { + const response = await axios.post( + "https://YOURSITE.azurewebsites.net/handle-queue", + { + id: context.bindingData.id, + message: myQueueItem, + meta: { + dequeueCount: context.bindingData.dequeueCount, + expirationTime: context.bindingData.expirationTime, + insertionTime: context.bindingData.insertionTime, + nextVisibleTime: context.bindingData.nextVisibleTime, + popReceipt: context.bindingData.popReceipt, + }, + } + ); + + context.log(response.data); + } catch (error) { + // If the promise rejects, an error will be thrown and caught here + context.log(error); + } + + context.done(); +}; ``` ## Testing diff --git a/src/Connector.php b/src/Connector.php index 803851c..f0a52f2 100644 --- a/src/Connector.php +++ b/src/Connector.php @@ -6,10 +6,15 @@ use MicrosoftAzure\Storage\Queue\QueueRestProxy; use Squigg\AzureQueueLaravel\AzureQueue; +/** + * Connector + */ class Connector implements ConnectorInterface { /** * Establish a queue connection. + * + * @param mixed $config */ public function connect(array $config): AzureQueue { diff --git a/src/Controller.php b/src/Controller.php index da1e264..3c688bc 100644 --- a/src/Controller.php +++ b/src/Controller.php @@ -6,6 +6,9 @@ use Illuminate\Support\Arr; use MicrosoftAzure\Storage\Queue\Models\QueueMessage; +/** + * Controller + */ class Controller { /** @@ -18,17 +21,25 @@ class Controller */ protected $jobHandler; + /** + * __construct + * + * @param mixed $jobHandler + * @return void + */ public function __construct(JobHandler $jobHandler) { $this->jobHandler = $jobHandler; } + /** + * handle + * + * @param mixed $request + * @return void + */ public function handle(JobRequest $request) { - \Log::info('We got some request', [ - 'request' => $request->all(), - ]); - $input = $request->validated(); $message = QueueMessage::createFromListMessages([ @@ -41,6 +52,10 @@ public function handle(JobRequest $request) 'MessageText' => json_encode(Arr::get($input, 'message')), ]); - return $this->jobHandler->handle($message, Arr::get($input, 'meta.queueName', null)); + $job = $this->jobHandler->handle($message, Arr::get($input, 'meta.queueName', null)); + + return [ + 'uuid' => $job->uuid(), + ]; } } diff --git a/src/JobHandler.php b/src/JobHandler.php index 63782ea..79d0f04 100644 --- a/src/JobHandler.php +++ b/src/JobHandler.php @@ -6,9 +6,18 @@ use MicrosoftAzure\Storage\Queue\Models\QueueMessage; use Squigg\AzureQueueLaravel\AzureJob; +/** + * JobHandler + */ class JobHandler { - public function handle(QueueMessage $message, ?string $queue = null): array + /** + * handle + * + * @param mixed $message + * @param mixed $queue + */ + public function handle(QueueMessage $message, ?string $queue = null): AzureJob { $job = new AzureJob( app('queue')->getContainer(), @@ -22,6 +31,8 @@ public function handle(QueueMessage $message, ?string $queue = null): array $options->backoff = config('azure-queue-laravel.worker.backoff', 60 * 5); $options->maxTries = config('azure-queue-laravel.worker.maxTries', 3); - return app('queue.worker')->process(app('queue')->getConnectionName(), $job, $options); + app('queue.worker')->process(app('queue')->getConnectionName(), $job, $options); + + return $job; } } diff --git a/src/JobRequest.php b/src/JobRequest.php index c8599a7..d9ee654 100644 --- a/src/JobRequest.php +++ b/src/JobRequest.php @@ -4,6 +4,9 @@ use Illuminate\Foundation\Http\FormRequest; +/** + * JobRequest + */ class JobRequest extends FormRequest { /** @@ -16,7 +19,7 @@ public function rules() return [ 'id' => 'required|string', 'message' => 'required|array', - 'message.uid' => 'required|string', + 'message.uuid' => 'required|string', 'message.displayName' => 'required|string', 'message.job' => 'required|string', 'message.data' => 'required|array', diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 5a5f443..6199f73 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -5,8 +5,16 @@ use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; +/** + * ServiceProvider + */ class ServiceProvider extends PackageServiceProvider { + /** + * configurePackage + * + * @param mixed $package + */ public function configurePackage(Package $package): void { /* @@ -21,7 +29,7 @@ public function configurePackage(Package $package): void } /** - * Bootstrap any application services. + * bootingPackage */ public function bootingPackage(): void {