Skip to content

Commit 8afe429

Browse files
committed
docs(scenarios): Add some documentation for multi-broker support
1 parent 4cec016 commit 8afe429

File tree

15 files changed

+4839
-2076
lines changed

15 files changed

+4839
-2076
lines changed

docs/docs/reactive-commons/1-getting-started.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ dependencies {
5050
}
5151
```
5252

53+
Note: If you will use Cloud Events, you should include the Cloud Events dependency:
54+
55+
```groovy
56+
dependencies {
57+
implementation 'io.cloudevents:cloudevents-json-jackson:4.0.1'
58+
}
59+
```
60+
61+
```groovy
62+
5363
### Configuration properties
5464
5565
Also you need to include the name for your app in the `application.properties`, it is important because this value will
@@ -206,6 +216,14 @@ dependencies {
206216
}
207217
```
208218

219+
Note: If you will use Cloud Events, you should include the Cloud Events dependency:
220+
221+
```groovy
222+
dependencies {
223+
implementation 'io.cloudevents:cloudevents-json-jackson:4.0.1'
224+
}
225+
```
226+
209227
### Configuration properties
210228

211229
Also you need to include the name for your app in the `application.properties`, it is important because this value will

docs/docs/reactive-commons/11-creating-a-cloud-event.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,19 @@ In order to instantiate a CloudEvent you may need to include the dependencies:
1616

1717
```groovy
1818
implementation 'io.cloudevents:cloudevents-core:<version>'
19+
// or
20+
implementation 'io.cloudevents:cloudevents-json-jackson:<version>'
21+
```
22+
23+
## Creating a CloudEvent instance with our Data wrapper
24+
25+
add this classes:
26+
27+
```java
28+
import io.cloudevents.core.builder.CloudEventBuilder;
29+
import io.cloudevents.CloudEvent;
30+
import org.reactivecommons.async.commons.converters.json.CloudEventBuilderExt;
1931
```
20-
## Creating a CloudEvent instance
2132

2233
```java
2334
CloudEvent commandCloudEvent = CloudEventBuilder.v1()
@@ -44,4 +55,44 @@ CloudEvent eventCloudEvent = CloudEventBuilder.v1()
4455
.withTime(OffsetDateTime.now())
4556
.withData("application/json", CloudEventBuilderExt.asCloudEventData(eventData)) // eventData is your own object
4657
.build();
58+
```
59+
60+
## Creating a CloudEvent instance with jackson wrapper Data wrapper
61+
62+
add this classes:
63+
64+
```java
65+
import io.cloudevents.core.builder.CloudEventBuilder;
66+
import io.cloudevents.CloudEvent;
67+
import io.cloudevents.jackson.JsonCloudEventData;
68+
import com.fasterxml.jackson.databind.ObjectMapper;
69+
```
70+
71+
```java
72+
ObjectMapper mapper = new ObjectMapper(); // You should convert your object to a JsonNode
73+
74+
CloudEvent commandCloudEvent = CloudEventBuilder.v1()
75+
.withId(UUID.randomUUID().toString())
76+
.withSource(URI.create("https://reactivecommons.org/foos"))
77+
.withType("some.command.name")
78+
.withTime(OffsetDateTime.now())
79+
.withData("application/json", JsonCloudEventData.wrap(mapper.valueToTree(commandData))) // commandData is your own object
80+
.build();
81+
82+
CloudEvent queryCloudEvent = CloudEventBuilder.v1()
83+
.withId(UUID.randomUUID().toString())
84+
.withSource(URI.create("https://reactivecommons.org/foos"))
85+
.withType("some.query.name")
86+
.withTime(OffsetDateTime.now())
87+
.withData("application/json", JsonCloudEventData.wrap(mapper.valueToTree(queryData))) // queryData is your own object
88+
.build();
89+
90+
CloudEvent eventCloudEvent = CloudEventBuilder.v1()
91+
.withId(UUID.randomUUID().toString())
92+
.withSource(URI.create("https://reactivecommons.org/foos"))
93+
.withType("some.event.name")
94+
.withDataContentType("application/json")
95+
.withTime(OffsetDateTime.now())
96+
.withData("application/json", JsonCloudEventData.wrap(mapper.valueToTree(eventData))) // eventData is your own object
97+
.build();
4798
```

docs/docs/reactive-commons/3-sending-a-command.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ public interface DirectAsyncGateway {
3939
}
4040
```
4141

42+
You can send a CloudEvent or a Command\<T> to a target application. You also can send a command to a specific domain
43+
(remote broker out of you application context).
44+
4245
## Enabling autoconfiguration
4346

4447
To send Commands you should enable the respecting spring boot autoconfiguration using the `@EnableDomainEventBus` annotation
@@ -50,7 +53,7 @@ For example:
5053
public class ReactiveDirectAsyncGateway {
5154
public static final String TARGET_NAME = "other-app";// refers to remote spring.application.name property
5255
public static final String SOME_COMMAND_NAME = "some.command.name";
53-
private final DirectAsyncGateway gateway; // Auto injectec bean created by the @EnableDirectAsyncGateway annotation
56+
private final DirectAsyncGateway gateway; // Auto injected bean created by the @EnableDirectAsyncGateway annotation
5457

5558
public Mono<Void> runRemoteJob(Object command/*change for proper model*/) {
5659
return gateway.sendCommand(new Command<>(SOME_COMMAND_NAME, UUID.randomUUID().toString(), command), TARGET_NAME);

docs/docs/reactive-commons/4-making-an-async-query.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public interface DirectAsyncGateway {
3838

3939
In this method the Class\<R> called type is the return type of the query, represented by a JSON Serializable object
4040

41+
You can send a CloudEvent or an AsyncQuery\<T> to a target application. You also can send a query to a specific domain
42+
(remote broker out of you application context).
43+
4144
## Enabling autoconfiguration
4245

4346
To do an Async Query you should enable the respecting spring boot autoconfiguration using the `@EnableDirectAsyncGateway` annotation

docs/docs/reactive-commons/5-handler-registry.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,24 @@ The next methods are the main methods that you can use to register a handler.
1616

1717
```java
1818
public class HandlerRegistry {
19-
public <T> HandlerRegistry listenEvent(String eventName, EventHandler<T> handler, Class<T> eventClass){...}
20-
public <T> HandlerRegistry handleDynamicEvents(String eventNamePattern, EventHandler<T> handler, Class<T> eventClass){...}
21-
public <T> HandlerRegistry listenNotificationEvent(String eventName, EventHandler<T> handler, Class<T> eventClass){...}
22-
public <T> HandlerRegistry handleCommand(String commandName, CommandHandler<T> fn, Class<T> commandClass){...}
23-
public <T, R> HandlerRegistry serveQuery(String resource, QueryHandler<T, R> handler, Class<R> queryClass){...}
24-
public <R> HandlerRegistry serveQuery(String resource, QueryHandlerDelegate<Void, R> handler, Class<R> queryClass) {...}
25-
// ... other methods for eda variant and overloads
19+
public <T> HandlerRegistry listenDomainEvent(String domain, String eventName, DomainEventHandler<T> handler, Class<T> eventClass)
20+
public HandlerRegistry listenDomainCloudEvent(String domain, String eventName, CloudEventHandler handler)
21+
public <T> HandlerRegistry listenEvent(String eventName, DomainEventHandler<T> handler, Class<T> eventClass)
22+
public HandlerRegistry listenCloudEvent(String eventName, CloudEventHandler handler)
23+
public <T> HandlerRegistry listenNotificationEvent(String eventName, DomainEventHandler<T> handler, Class<T> eventClass)
24+
public HandlerRegistry listenNotificationCloudEvent(String eventName, CloudEventHandler handler)
25+
public <T> HandlerRegistry handleDynamicEvents(String eventNamePattern, DomainEventHandler<T> handler, Class<T> eventClass)
26+
public HandlerRegistry handleDynamicCloudEvents(String eventNamePattern, CloudEventHandler handler)
27+
public <T> HandlerRegistry handleCommand(String commandName, DomainCommandHandler<T> fn, Class<T> commandClass)
28+
public HandlerRegistry handleCloudEventCommand(String commandName, CloudCommandHandler handler)
29+
public <T, R> HandlerRegistry serveQuery(String resource, QueryHandler<T, R> handler, Class<R> queryClass)
30+
public <R> HandlerRegistry serveQuery(String resource, QueryHandlerDelegate<Void, R> handler, Class<R> queryClass)
31+
public <R> HandlerRegistry serveCloudEventQuery(String resource, QueryHandler<R, CloudEvent> handler)
32+
public <R> HandlerRegistry serveCloudEventQuery(String resource, QueryHandlerDelegate<Void, CloudEvent> handler)
2633
}
27-
```
34+
```
35+
36+
Methods that Has `CloudEvent` in the name are related to the CloudEvent specification.
37+
38+
Methods that has `domain` String argument are related to the multi-broker support, this support is limited to listen events
39+
from different domains (brokers) independent of the technology.
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
---
2+
sidebar_position: 1
3+
---
4+
5+
# Single Broker
6+
7+
import Tabs from '@theme/Tabs';
8+
import TabItem from '@theme/TabItem';
9+
import ThemeImage from '../../src/components/ThemeImage';
10+
11+
<ThemeImage scenario="1"></ThemeImage>
12+
13+
Both apps the `App 1` and the `App 2` are connected to the same `Broker`, so both has the same connection configuration,
14+
and `Broker` is considered the `app` domain for both apps.
15+
16+
<Tabs>
17+
<TabItem value="rabbitmq" label="RabbitMQ" default>
18+
19+
You can customize some predefined variables of Reactive Commons
20+
21+
This can be done by Spring Boot `application.yaml` or by overriding
22+
the [AsyncProps](https://github.com/reactive-commons/reactive-commons-java/blob/master/starters/async-rabbit-starter/src/main/java/org/reactivecommons/async/rabbit/config/props/AsyncProps.java)
23+
bean.
24+
25+
```yaml
26+
app:
27+
async:
28+
app: # this is the name of the default domain
29+
withDLQRetry: false # if you want to have dlq queues with retries you can set it to true, you cannot change it after queues are created, because you will get an error, so you should delete topology before the change.
30+
maxRetries: -1 # -1 will be considered default value. When withDLQRetry is true, it will be retried 10 times. When withDLQRetry is false, it will be retried indefinitely.
31+
retryDelay: 1000 # interval for message retries, with and without DLQRetry
32+
listenReplies: true # if you will not use ReqReply patter you can set it to false
33+
createTopology: true # if your organization have restrictions with automatic topology creation you can set it to false and create it manually or by your organization process.
34+
delayedCommands: false # Enable to send a delayed command to an external target
35+
prefetchCount: 250 # is the maximum number of in flight messages you can reduce it to process less concurrent messages, this settings acts per instance of your service
36+
useDiscardNotifierPerDomain: false # if true it uses a discard notifier for each domain,when false it uses a single discard notifier for all domains with default 'app' domain
37+
enabled: true # if you want to disable this domain you can set it to false
38+
brokerType: "rabbitmq" # please don't change this value
39+
flux:
40+
maxConcurrency: 250 # max concurrency of listener flow
41+
domain:
42+
ignoreThisListener: false # Allows you to disable event listener for this specific domain
43+
events:
44+
exchange: domainEvents # you can change the exchange, but you should do it in all applications consistently
45+
eventsSuffix: subsEvents # events queue name suffix, name will be like ${spring.application.name}.${app.async.domain.events.eventsSuffix}
46+
notificationSuffix: notification # notification events queue name suffix
47+
direct:
48+
exchange: directMessages # you can change the exchange, but you should do it in all applications
49+
querySuffix: query # queries queue name suffix, name will be like ${spring.application.name}.${app.async.direct.querySuffix}
50+
commandSuffix: '' # commands queue name suffix, name will be like ${spring.application.name}.${app.async.direct.querySuffix} or ${spring.application.name} if empty by default
51+
discardTimeoutQueries: false # enable to discard this condition
52+
global:
53+
exchange: globalReply # you can change the exchange, but you should do it in all applications
54+
repliesSuffix: replies # async query replies events queue name suffix
55+
connectionProperties: # you can override the connection properties of each domain
56+
host: localhost
57+
port: 5672
58+
username: guest
59+
password: guest
60+
virtual-host: /
61+
```
62+
63+
You can override this settings programmatically through a `AsyncPropsDomainProperties` bean.
64+
65+
```java
66+
package sample;
67+
68+
import org.reactivecommons.async.rabbit.config.RabbitProperties;
69+
import org.reactivecommons.async.rabbit.config.props.AsyncProps;
70+
import org.reactivecommons.async.rabbit.config.props.AsyncRabbitPropsDomainProperties;
71+
import org.springframework.context.annotation.Bean;
72+
import org.springframework.context.annotation.Primary;
73+
74+
@Configuration
75+
public class MyDomainConfig {
76+
77+
@Bean
78+
@Primary
79+
public AsyncPropsDomainProperties customDomainProperties() {
80+
RabbitProperties propertiesApp = new RabbitProperties();
81+
propertiesApp.setHost("localhost");
82+
propertiesApp.setPort(5672);
83+
propertiesApp.setVirtualHost("/");
84+
propertiesApp.setUsername("guest");
85+
propertiesApp.setPassword("guest");
86+
87+
return AsyncPropsDomainProperties.builder()
88+
.withDomain("app", AsyncProps.builder()
89+
.connectionProperties(propertiesApp)
90+
.build())
91+
.build();
92+
}
93+
}
94+
```
95+
96+
Additionally, if you want to set only connection properties you can use the `AsyncPropsDomain.SecretFiller` class.
97+
98+
```java
99+
100+
@Bean
101+
@Primary
102+
public AsyncPropsDomain.SecretFiller customFiller() {
103+
return (domain, asyncProps) -> {
104+
// customize asyncProps here by domain
105+
};
106+
}
107+
```
108+
109+
</TabItem>
110+
<TabItem value="kafka" label="Kafka">
111+
You can customize some predefined variables of Reactive Commons
112+
113+
This can be done by Spring Boot `application.yaml` or by overriding
114+
the [AsyncKafkaProps](https://github.com/reactive-commons/reactive-commons-java/blob/master/starters/async-kafka-starter/src/main/java/org/reactivecommons/async/kafka/config/props/AsyncKafkaProps.java)
115+
bean.
116+
117+
```yaml
118+
reactive:
119+
commons:
120+
kafka:
121+
app: # this is the name of the default domain
122+
withDLQRetry: false # if you want to have dlq queues with retries you can set it to true, you cannot change it after queues are created, because you will get an error, so you should delete topology before the change.
123+
maxRetries: -1 # -1 will be considered default value. When withDLQRetry is true, it will be retried 10 times. When withDLQRetry is false, it will be retried indefinitely.
124+
retryDelay: 1000 # interval for message retries, with and without DLQRetry
125+
checkExistingTopics: true # if you don't want to verify topic existence before send a record you can set it to false
126+
createTopology: true # if your organization have restrictions with automatic topology creation you can set it to false and create it manually or by your organization process.
127+
useDiscardNotifierPerDomain: false # if true it uses a discard notifier for each domain,when false it uses a single discard notifier for all domains with default 'app' domain
128+
enabled: true # if you want to disable this domain you can set it to false
129+
brokerType: "kafka" # please don't change this value
130+
domain:
131+
ignoreThisListener: false # Allows you to disable event listener for this specific domain
132+
connectionProperties: # you can override the connection properties of each domain
133+
bootstrap-servers: localhost:9092
134+
```
135+
136+
You can override this settings programmatically through a `AsyncKafkaPropsDomainProperties` bean.
137+
138+
```java
139+
package sample;
140+
141+
import org.reactivecommons.async.kafka.config.KafkaProperties;
142+
import org.reactivecommons.async.kafka.config.props.AsyncProps;
143+
import org.reactivecommons.async.kafka.config.props.AsyncKafkaPropsDomainProperties;
144+
import org.springframework.context.annotation.Bean;
145+
import org.springframework.context.annotation.Primary;
146+
147+
@Configuration
148+
public class MyDomainConfig {
149+
150+
@Bean
151+
@Primary
152+
public AsyncKafkaPropsDomainProperties customKafkaDomainProperties() {
153+
KafkaProperties propertiesApp = new KafkaProperties();
154+
propertiesApp.setBootstrapServers(List.of("localhost:9092"));
155+
156+
return AsyncKafkaPropsDomainProperties.builder()
157+
.withDomain("app", AsyncProps.builder()
158+
.connectionProperties(propertiesApp)
159+
.build())
160+
.build();
161+
}
162+
}
163+
```
164+
165+
Additionally, if you want to set only connection properties you can use the `AsyncKafkaPropsDomain.KafkaSecretFiller`
166+
class.
167+
168+
```java
169+
170+
@Bean
171+
@Primary
172+
public AsyncKafkaPropsDomain.KafkaSecretFiller customKafkaFiller() {
173+
return (domain, asyncProps) -> {
174+
// customize asyncProps here by domain
175+
};
176+
}
177+
```
178+
179+
</TabItem>
180+
</Tabs>

0 commit comments

Comments
 (0)