178 lines
4.5 KiB
Plaintext
178 lines
4.5 KiB
Plaintext
[[rabbit-receiving-batch]]
|
|
= Receiving Batched Messages
|
|
|
|
With the RabbitMQ binder, there are two types of batches handled by consumer bindings:
|
|
|
|
[[batches-created-by-producers]]
|
|
== Batches Created by Producers
|
|
|
|
Normally, if a producer binding has `batch-enabled=true` (see xref:rabbit/rabbit_overview/prod-props.adoc[Rabbit Producer Properties]), or a message is created by a `BatchingRabbitTemplate`, elements of the batch are returned as individual calls to the listener method.
|
|
Starting with version 3.0, any such batch can be presented as a `List<?>` to the listener method if `spring.cloud.stream.bindings.<name>.consumer.batch-mode` is set to `true`.
|
|
|
|
[[consumer-side-batching]]
|
|
== Consumer-side Batching
|
|
|
|
Starting with version 3.1, the consumer can be configured to assemble multiple inbound messages into a batch which is presented to the application as a `List<?>` of converted payloads.
|
|
The following simple application demonstrates how to use this technique:
|
|
|
|
[source, properties]
|
|
----
|
|
spring.cloud.stream.bindings.input-in-0.group=someGroup
|
|
|
|
spring.cloud.stream.bindings.input-in-0.consumer.batch-mode=true
|
|
|
|
spring.cloud.stream.rabbit.bindings.input-in-0.consumer.enable-batching=true
|
|
spring.cloud.stream.rabbit.bindings.input-in-0.consumer.batch-size=10
|
|
spring.cloud.stream.rabbit.bindings.input-in-0.consumer.receive-timeout=200
|
|
----
|
|
|
|
[source, java]
|
|
----
|
|
@SpringBootApplication
|
|
public class Application {
|
|
|
|
public static void main(String[] args) {
|
|
SpringApplication.run(Application.class, args);
|
|
}
|
|
|
|
@Bean
|
|
Consumer<List<Thing>> input() {
|
|
return list -> {
|
|
System.out.println("Received " + list.size());
|
|
list.forEach(thing -> {
|
|
System.out.println(thing);
|
|
|
|
// ...
|
|
|
|
});
|
|
};
|
|
}
|
|
|
|
@Bean
|
|
public ApplicationRunner runner(RabbitTemplate template) {
|
|
return args -> {
|
|
template.convertAndSend("input-in-0.someGroup", "{\"field\":\"value1\"}");
|
|
template.convertAndSend("input-in-0.someGroup", "{\"field\":\"value2\"}");
|
|
};
|
|
}
|
|
|
|
public static class Thing {
|
|
|
|
private String field;
|
|
|
|
public Thing() {
|
|
}
|
|
|
|
public Thing(String field) {
|
|
this.field = field;
|
|
}
|
|
|
|
public String getField() {
|
|
return this.field;
|
|
}
|
|
|
|
public void setField(String field) {
|
|
this.field = field;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "Thing [field=" + this.field + "]";
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
----
|
|
|
|
[source]
|
|
----
|
|
Received 2
|
|
Thing [field=value1]
|
|
Thing [field=value2]
|
|
----
|
|
|
|
The number of messages in a batch is specified by the `batch-size` and `receive-timeout` properties; if the `receive-timeout` elapses with no new messages, a "short" batch is delivered.
|
|
|
|
IMPORTANT: Consumer-side batching is only supported with `container-type=simple` (the default).
|
|
|
|
If you wish to examine headers of consumer-side batched messages, you should consume `Message<List<?>>`; the headers are a `List<Map<String, Object>>` in a header `AmqpInboundChannelAdapter.CONSOLIDATED_HEADERS`, with the headers for each payload element in the corresponding index.
|
|
Again, here is a simple example:
|
|
|
|
[source, java]
|
|
----
|
|
@SpringBootApplication
|
|
public class Application {
|
|
|
|
public static void main(String[] args) {
|
|
SpringApplication.run(Application.class, args);
|
|
}
|
|
|
|
@Bean
|
|
Consumer<Message<List<Thing>>> input() {
|
|
return msg -> {
|
|
List<Thing> things = msg.getPayload();
|
|
System.out.println("Received " + things.size());
|
|
@SuppressWarnings("unchecked")
|
|
List<Map<String, Object>> headers =
|
|
(List<Map<String, Object>>) msg.getHeaders().get(AmqpInboundChannelAdapter.CONSOLIDATED_HEADERS);
|
|
for (int i = 0; i < things.size(); i++) {
|
|
System.out.println(things.get(i) + " myHeader=" + headers.get(i).get("myHeader"));
|
|
|
|
// ...
|
|
|
|
}
|
|
};
|
|
}
|
|
|
|
@Bean
|
|
public ApplicationRunner runner(RabbitTemplate template) {
|
|
return args -> {
|
|
template.convertAndSend("input-in-0.someGroup", "{\"field\":\"value1\"}", msg -> {
|
|
msg.getMessageProperties().setHeader("myHeader", "headerValue1");
|
|
return msg;
|
|
});
|
|
template.convertAndSend("input-in-0.someGroup", "{\"field\":\"value2\"}", msg -> {
|
|
msg.getMessageProperties().setHeader("myHeader", "headerValue2");
|
|
return msg;
|
|
});
|
|
};
|
|
}
|
|
|
|
public static class Thing {
|
|
|
|
private String field;
|
|
|
|
public Thing() {
|
|
}
|
|
|
|
public Thing(String field) {
|
|
this.field = field;
|
|
}
|
|
|
|
public String getfield() {
|
|
return this.field;
|
|
}
|
|
|
|
public void setfield(String field) {
|
|
this.field = field;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "Thing [field=" + this.field + "]";
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
----
|
|
|
|
[source]
|
|
----
|
|
Received 2
|
|
Thing [field=value1] myHeader=headerValue1
|
|
Thing [field=value2] myHeader=headerValue2
|
|
----
|
|
|