You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Remove usage of the interface
* Move multiple sagas stuff into partial
* Analyzer partials for not found handler changes
* Fix text
* Extend snippet with not found handler mapping
* Tweak tutorial to no longer use the interface
* Upgrade guide
* Grammar
Co-authored-by: Copilot <[email protected]>
* Configured handlers
* Be more specific
---------
Co-authored-by: Daniel Marbach <[email protected]>
Co-authored-by: Copilot <[email protected]>
Copy file name to clipboardExpand all lines: nservicebus/sagas/analyzers.md
+2-8Lines changed: 2 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -138,17 +138,11 @@ Sagas should not use a base class (i.e. `MySaga : MyAbstractSaga<TSagaData>`) to
138
138
139
139
A better way to provide shared functionality to multiple saga types and reduce code duplication is to use [extension methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods).
140
140
141
-
## Saga should not implement IHandleSagaNotFound
141
+
## Saga should not implement saga not found handler
142
142
143
143
***Rule ID**: NSB0015
144
144
***Severity**: Warning, Error starting in NServiceBus version 8
145
-
***Example message**: A saga should not implement `IHandleSagaNotFound`, as this catch-all handler will handle messages where *any* saga is not found. Implement `IHandleSagaNotFound` on a separate class instead.
146
-
147
-
A ["saga not found" handler](/nservicebus/sagas/saga-not-found.md) provides a way to deal with messages that are not allowed to start a saga but cannot find existing saga data.
148
-
149
-
"Saga not found" handlers operate on all saga messages within an endpoint, no matter which saga the message was originally bound for. So it is misleading to implement `IHandleSagaNotFound` on a saga because it creates the impression that it will only handle not found messages for that _specific_ saga, which is false.
150
-
151
-
Instead, implement `IHandleSagaNotFound` on an independent class.
145
+
partial: not-found-handler
152
146
153
147
## Correlation property must match message mapping expression type
***Example message**: A saga should not implement `IHandleSagaNotFound`, as this catch-all handler will handle messages where *any* saga is not found. Implement `IHandleSagaNotFound` on a separate class instead.
2
+
3
+
A [saga not found handler](/nservicebus/sagas/saga-not-found.md) provides a way to deal with messages that are not allowed to start a saga but cannot find existing saga data.
4
+
5
+
Saga not found handlers operate on all saga messages within an endpoint, no matter which saga the message was originally bound for. So it is misleading to implement `IHandleSagaNotFound` on a saga because it creates the impression that it will only handle not found messages for that _specific_ saga, which is false.
6
+
7
+
Instead, implement `IHandleSagaNotFound` on an independent class.
***Example message**: A saga should not implement `ISagaNotFoundHandler`, as this gives access to the uninitialized saga data property. Implement `ISagaNotFoundHandler` on a separate class instead.
2
+
3
+
A [saga not found handler](/nservicebus/sagas/saga-not-found.md) provides a way to deal with messages that are not allowed to start a saga but cannot find existing saga data.
4
+
5
+
Saga not found handlers may require specific dependencies to be injected into the class and may implement non-trivial handling logic. To separate those concerns from the saga an independent class should implement `ISagaNotFoundHandler` and be mapped with `mapper.ConfigureNotFoundHandler<MyNotFoundHandler>()`.
Copy file name to clipboardExpand all lines: nservicebus/sagas/index.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -72,7 +72,7 @@ Messages can be delivered out of order, e.g. due to error recovery, network late
72
72
To ensure messages are not discarded when they arrive out of order:
73
73
74
74
- Implement multiple `IAmStartedByMessages<T>` interfaces for any message type that assumes the saga instance should already exist
75
-
- Override the saga not found behavior and throw an exception using `IHandleSagaNotFound` and rely on NServiceBus recoverability capability to retry messages to resolve out-of-order issues.
75
+
- Override the saga not found behavior and throw an exception using a saga not found handler and rely on NServiceBus recoverability capability to retry messages to resolve out-of-order issues.
76
76
77
77
#### Multiple message types starting a saga
78
78
@@ -86,7 +86,7 @@ When messages arrive in reverse order, the handler for the `CompleteOrder` messa
86
86
87
87
In most scenarios, an acceptable solution to deal with out-of-order message delivery is to throw an exception when the saga instance does not exist. The message will be automatically retried, which may resolve the issue; otherwise, it will be placed in the error queue, where it can be manually retried.
88
88
89
-
To override the default saga not found behavior [implement `IHandleSagaNotFound` and throw an exception](saga-not-found.md).
89
+
To override the default saga not found behavior [implement a saga not found handler and throw an exception](saga-not-found.md).
90
90
91
91
## Correlating messages to a saga
92
92
@@ -107,13 +107,13 @@ Instance cleanup is implemented differently by the various saga persisters and i
107
107
108
108
### Outstanding timeouts
109
109
110
-
Outstanding timeouts requested by the saga instance will be discarded when they expire without triggering the [`IHandleSagaNotFound` API](saga-not-found.md)
110
+
Outstanding timeouts requested by the saga instance will be discarded when they expire without triggering the [saga not found handler](saga-not-found.md)
111
111
112
112
### Messages arriving after a saga has been completed
113
113
114
114
Messages that [are allowed to start a new saga instance](#starting-a-saga) will cause a new instance with the same correlation id to be created.
115
115
116
-
Messages handled by the saga (`IHandleMessages<T>`) that arrive after the saga has completed will be passed to the [`IHandleSagaNotFound` API](saga-not-found.md).
116
+
Messages handled by the saga (`IHandleMessages<T>`) that arrive after the saga has completed will be passed to the [saga not found handler](saga-not-found.md).
Copy file name to clipboardExpand all lines: nservicebus/sagas/saga-not-found.md
+6-14Lines changed: 6 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,29 +7,21 @@ related:
7
7
- samples/saga
8
8
---
9
9
10
-
The messages that are handled by sagas can either start a new saga (if handled by `IAmStartedByMessages<T>`) or update an existing saga (if handled by `IHandleMessages<T>`). If the incoming message is meant to be handled by a saga but is not expected to start a new one, then NServiceBus uses [correlation rules](/nservicebus/sagas/#correlating-messages-to-a-saga) to find an existing saga. If no existing saga can be found, all implementations of `IHandleSagaNotFound`are executed. If no implementation can be found, the message is discarded without additional notification.
10
+
The messages that are handled by sagas can either start a new saga (if handled by `IAmStartedByMessages<T>`) or update an existing saga (if handled by `IHandleMessages<T>`). If the incoming message is meant to be handled by a saga but is not expected to start a new one, then NServiceBus uses [correlation rules](/nservicebus/sagas/#correlating-messages-to-a-saga) to find an existing saga. If no existing saga can be found, configured saga not found handlers are executed. If no handler is configured, the message is discarded without additional notification.
11
11
12
12
snippet: saga-not-found
13
13
14
-
Note that in the example above, the message will be considered successfully processed and sent to the audit queue even if no saga was found. Throw an exception from the `IHandleSagaNotFound` implementation to move the message to the error queue.
14
+
Note that in the example above, the message will be considered successfully processed and sent to the audit queue even if no saga was found. Throw an exception from the saga not found handler implementation to move the message to the error queue.
15
15
16
-
> [!NOTE]
17
-
> If there are multiple saga types that handle a given message type and one of them is found while others are not, the `IHandleSagaNotFound` handlers **will not be executed**. The `IHandleSagaNotFound` handlers are executed only if no saga instances are invoked. The following table illustrates when the `IHandleSagaNotFound` handlers are invoked when a message is mapped to two different saga types, A and B.
18
-
19
-
| Saga A found | Saga B found | Not found handler invoked |
20
-
|--------|--------|---------|
21
-
| ✔️ | ✔️ | ❌ |
22
-
| ✔️ | ❌ | ❌ |
23
-
| ❌ | ✔️ | ❌ |
24
-
| ❌ | ❌ | ✔️ |
16
+
partial: multiple-sagas
25
17
26
18
include: non-null-task
27
19
28
-
The ability to provide an implementation for `IHandleSagaNotFound` is especially useful if compensating actions are needed for messages that arrive after the saga has been marked as complete. This is a common scenario when using timeouts inside the saga.
20
+
Implementing a saga not found handler is especially useful if compensating actions are needed for messages that arrive after the saga has been marked as complete. This is a common scenario when using timeouts inside the saga.
29
21
30
-
For example, consider a saga used to manage the registration process on the website. After a customer registers, they receive an email with a confirmation link. The system will wait for confirmation for a specific period of time, e.g., 24 hours. If the user doesn't click the link within 24 hours, their data is removed from the system, and the saga is completed. However, they might decide to click the confirmation link a few days later. In this case, the related saga instance can't be found, and an exception will be thrown. By implementing `IHandleSagaNotFound`, it is possible to handle the situation differently, e.g., redirect the user to the registration website and ask them to fill out the form again.
22
+
For example, consider a saga used to manage the registration process on the website. After a customer registers, they receive an email with a confirmation link. The system will wait for confirmation for a specific period of time, e.g., 24 hours. If the user doesn't click the link within 24 hours, their data is removed from the system, and the saga is completed. However, they might decide to click the confirmation link a few days later. In this case, the related saga instance can't be found, and an exception will be thrown. By implementing a saga not found handler, it is possible to handle the situation differently, e.g., redirect the user to the registration website and ask them to fill out the form again.
31
23
32
-
The implementation of `IHandleSagaNotFound`should be driven by the business requirements for a specific situation. In some cases, the message might be ignored; in others, it might be useful to track whenever that situation happens (e.g., by logging or sending another message). In other cases, it might make sense to perform a custom compensating action. For example, should it be necessary in some rare cases to move the message that did not find a saga to the error queue, it is possible to introduce a custom exception type (e.g`SagaNotFoundFoundException`)
24
+
The implementation of a saga not found handler should be driven by the business requirements for a specific situation. In some cases, the message might be ignored; in others, it might be useful to track whenever that situation happens (e.g., by logging or sending another message). In other cases, it might make sense to perform a custom compensating action. For example, should it be necessary in some rare cases to move the message that did not find a saga to the error queue, it is possible to introduce a custom exception type (e.g. `SagaNotFoundException`).
> If there are multiple saga types that handle a given message type and one of them is found while others are not, the saga not found handlers **will not be executed**. The saga not found handlers are executed only if no saga instances are invoked. The following table illustrates when the saga not found handlers are invoked when a message is mapped to two different saga types, A and B.
3
+
4
+
| Saga A found | Saga B found | Not found handler invoked |
Copy file name to clipboardExpand all lines: nservicebus/upgrades/9to10/index.md
+12-1Lines changed: 12 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -44,11 +44,22 @@ If message contracts are not in a versioned library, a local copy of the message
44
44
45
45
## Sagas
46
46
47
+
### Not found handlers
48
+
49
+
In Version 10 the `IHandleSagaNotFound` interface has been deprecated in favour of `ISagaNotFoundHandler`. The [saga not found handlers](/nservicebus/sagas/saga-not-found.md) are no longer automatically registered via assembly scanning and must be mapped in the `ConfigureHowToFindSaga` method of the sagas that require the not found handler to be executed:
In Version 10 [custom saga finders](/nservicebus/sagas/saga-finding.md) are no longer automatically registered via assembly scanning and must be mapped in the `ConfigureHowToFindSaga` method:
0 commit comments