Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,25 @@

namespace App\Dispatcher;

use Ibexa\Bundle\Messenger\Stamp\DeduplicateStamp;
use Symfony\Component\Messenger\Envelope;
use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Messenger\Stamp\SudoStamp;
use Ibexa\Contracts\Messenger\Stamp\UserPermissionStamp;
use Symfony\Component\Messenger\MessageBusInterface;

final readonly class SomeClassThatSchedulesExecutionInTheBackground
{
public function __construct(private MessageBusInterface $bus)
{
public function __construct(
private MessageBusInterface $bus,
private PermissionResolver $permissionResolver,
) {
}

public function schedule(object $message): void
{
// Dispatch directly. Message is wrapped with envelope without any stamps.
$this->bus->dispatch($message);

// Alternatively, wrap with stamps. In this case, DeduplicateStamp ensures
// that if similar command exists in the queue (or is being processed)
// it will not be queued again.
$envelope = Envelope::wrap(
$message,
[new DeduplicateStamp('command-name-1')]
);

$this->bus->dispatch($envelope);
$currentUserId = $this->permissionResolver->getCurrentUserReference()->getUserId();
$this->bus->dispatch($message, [new UserPermissionStamp($currentUserId)]);
$this->bus->dispatch($message, [new SudoStamp()]);
}
}
2 changes: 0 additions & 2 deletions deptrac.baseline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ deptrac:
- Ibexa\Discounts\Value\AbstractDiscountExpressionAware
App\Discounts\Rule\PurchasingPowerParityRuleFactory:
- Ibexa\Discounts\Repository\DiscountRule\DiscountRuleFactoryInterface
App\Dispatcher\SomeClassThatSchedulesExecutionInTheBackground:
- Ibexa\Bundle\Messenger\Stamp\DeduplicateStamp
App\EventListener\TextAnchorMenuTabListener:
- Ibexa\AdminUi\Menu\ContentEditAnchorMenuBuilder
- Ibexa\AdminUi\Menu\Event\ConfigureMenuEvent
Expand Down
2 changes: 1 addition & 1 deletion docs/content_management/data_migration/importing_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ You can run a set of one or more similar migration steps multiple times by using

A repeatable migration performs the defined migration steps as many times as specified:

- with an [interation counter](#repeatable-steps-with-iteration-counter), mimicking the behavior of a [`for` loop](https://www.php.net/manual/en/control-structures.for.php)
- with an [iteration counter](#repeatable-steps-with-iteration-counter), mimicking the behavior of a [`for` loop](https://www.php.net/manual/en/control-structures.for.php)
- with a [list of items](#repeatable-steps-with-items), mimicking the behavior of a [`foreach` loop](https://www.php.net/manual/en/control-structures.foreach.php)

!!! tip
Expand Down
74 changes: 66 additions & 8 deletions docs/infrastructure_and_maintenance/background_tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
The process works as follows:

1. A message PHP object is dispatched, for example, `ProductPriceReindex`.
2. The message is wrapped in an envelope, which may contain additional metadata, called stamps, for example, `DeduplicateStamp`.
2. The message is wrapped in an envelope, which may contain additional metadata, called [stamps](#stamps).

Check notice on line 24 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L24

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 24, "column": 16}}}, "severity": "INFO"}
3. The message is placed in the transport queue.
It can be a Doctrine table, a Redis/Valkey queue, and so on.
4. A worker process continuously reads messages from the queue, pulls them into the default bus `ibexa.messenger.bus` and assigns them to the right handler.
Expand Down Expand Up @@ -92,25 +92,83 @@

If you deploy your application on [[= product_name_cloud =]], using [Workers](https://fixed.docs.upsun.com/guides/symfony/workers.html) is recommended.

### Dispatch message
## Dispatch message

Dispatch a message from your code like in the following example:
To have a task processed in the background, dispatch an appropriate message by using the `\Symfony\Component\Messenger\MessageBusInterfac\MessageBusInterface::dispatch()` method, exactly as described in [Symfony Messenger documentation]([[= symfony_doc =]]/messenger.html#dispatching-the-message):

``` php
[[= include_code("code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php") =]]
[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 1, 3) =]]

[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 8, 13) =]]
[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 15, 20) =]]
[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 25, 26) =]]
```

### Register handler
Additionally, attach message metadata by using [stamps](#stamps).

### Stamps

You can attach [Stamps]([[= symfony_doc =]]/messenger.html#envelopes-stamps) to a message envelope to add additional metadata and control how the message is processed.

Check notice on line 111 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L111

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 111, "column": 155}}}, "severity": "INFO"}

Use [Stamps available in Symfony](https://github.com/symfony/symfony/tree/[[= symfony_version =]]/src/Symfony/Component/Messenger/Stamp), and combine them with the ones provided by [[= product_name =]]:

Check failure on line 113 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L113

[Ibexa.Spellcheck] Did you really mean 'symfony_version'?
Raw output
{"message": "[Ibexa.Spellcheck] Did you really mean 'symfony_version'?", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 113, "column": 79}}}, "severity": "ERROR"}

- [SudoStamp](#sudostamp)
- [UserPermissionStamp](#userpermissionstamp)

#### SudoStamp

Check notice on line 118 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L118

[Ibexa.SentenceCapitalizationInHeadings] Use sentence-style capitalization in headings
Raw output
{"message": "[Ibexa.SentenceCapitalizationInHeadings] Use sentence-style capitalization in headings", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 118, "column": 6}}}, "severity": "INFO"}

[`SudoStamp`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Messenger-Stamp-SudoStamp.html) causes the handler to [use sudo mode](php_api.md#using-sudo), bypassing all permission checks when processing the message.

It's automatically attached to every dispatched message.

Create the handler class:
!!! caution

Starting with Ibexa DXP 5.0.9, the behavior of automatically attaching a `SudoStamp` to every message is deprecated and will be removed in 6.0.
For messages that should be processed without taking permissions into account, always attach the `SudoStamp` manually to keep your code forward-compatible.

The following example shows how you can attach the `SudoStamp` to the message:

``` php
[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 6, 6, remove_indent=True) =]]
[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 8, 9, remove_indent=True) =]]

[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 24, 24, remove_indent=True) =]]
```

#### UserPermissionStamp

Check notice on line 138 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L138

[Ibexa.SentenceCapitalizationInHeadings] Use sentence-style capitalization in headings
Raw output
{"message": "[Ibexa.SentenceCapitalizationInHeadings] Use sentence-style capitalization in headings", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 138, "column": 6}}}, "severity": "INFO"}

[`UserPermissionStamp`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Messenger-Stamp-UserPermissionStamp.html) allows you to [set the repository user](php_api.md#setting-the-repository-user) to process the message.
When the user is set, handlers execute actions on their behalf and take their permissions into account.

If you don't attach this stamp, the messages are processed by the default repository user called anonymous user.

Check notice on line 143 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L143

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 143, "column": 46}}}, "severity": "INFO"}
By combing this stamp with [`SudoStamp`](#sudostamp), you can set the repository user and skip the permission checks at the same time.

The following example shows how you can use `UserPermissionStamp` to preserve the current repository user after the message is dispatched.

Check notice on line 146 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L146

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 146, "column": 125}}}, "severity": "INFO"}

``` php
[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 5, 5, remove_indent=True) =]]
[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 7, 9, remove_indent=True) =]]

[[= include_code('code_samples/background_tasks/src/Dispatcher/SomeClassThatSchedulesExecutionInTheBackground.php', 22, 23, remove_indent=True) =]]
```

## Extend Ibexa Messenger

Check notice on line 155 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L155

[Ibexa.SentenceCapitalizationInHeadings] Use sentence-style capitalization in headings
Raw output
{"message": "[Ibexa.SentenceCapitalizationInHeadings] Use sentence-style capitalization in headings", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 155, "column": 4}}}, "severity": "INFO"}

Check failure on line 155 in docs/infrastructure_and_maintenance/background_tasks.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/infrastructure_and_maintenance/background_tasks.md#L155

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "docs/infrastructure_and_maintenance/background_tasks.md", "range": {"start": {"line": 155, "column": 11}}}, "severity": "ERROR"}

### Register custom message and handler

To handle additional use cases with background tasks, you can create [custom message and handler class]([[= symfony_doc =]]/messenger.html#creating-a-message-handler):

``` php
[[= include_code('code_samples/background_tasks/src/Message/SomeMessage.php') =]]
```

``` php
[[= include_code("code_samples/background_tasks/src/MessageHandler/SomeHandler.php") =]]
```

Add a service definition to `config/services.yaml`:
Add a service definition to `config/services.yaml` and set the `bus` to `ibexa.messenger.bus`:

``` yaml
``` yaml hl_lines="4-5"
services:
App\MessageHandler\SomeHandler:
tags:
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,7 @@ extra:
latest_tag_4_6: '4.6.31'
latest_tag_5_0: '5.0.9'

symfony_version: '7.4'
symfony_doc: 'https://symfony.com/doc/7.4'
user_doc: 'https://doc.ibexa.co/projects/userguide/en/5.0'
connect_doc: 'https://doc.ibexa.co/projects/connect/en/latest'
Expand Down
Loading