From dc1d1868d91837726a48d9f2966642a7d354151b Mon Sep 17 00:00:00 2001 From: Gunnar Hillert Date: Thu, 16 Feb 2012 12:18:41 -0500 Subject: [PATCH] INT-2430 - Improve Polling Consumer Documentation INT-2425 - Poller: Document the Ability to Change Polling Rate at Runtime For reference see: * https://jira.springsource.org/browse/INT-2430 * https://jira.springsource.org/browse/INT-2425 INT-2430 - Code Review - Minor spelling error fix in src/reference/docbook/endpoint.xml INT-2430 - Code Review - Doc updates * Add more documentation around the dynamic poller sample * Standardize Endpoint chapter so that for emphasis of properties the docbook element is used rather than quotes. Polishing --- src/reference/docbook/endpoint.xml | 399 ++++++++++++++++--- src/reference/docbook/messaging-channels.xml | 1 + src/reference/docbook/polling-consumer.xml | 71 ++++ 3 files changed, 409 insertions(+), 62 deletions(-) create mode 100644 src/reference/docbook/polling-consumer.xml diff --git a/src/reference/docbook/endpoint.xml b/src/reference/docbook/endpoint.xml index 80b6952654..72aec1850e 100644 --- a/src/reference/docbook/endpoint.xml +++ b/src/reference/docbook/endpoint.xml @@ -25,8 +25,8 @@ Message Channel, some component has to schedule and manage the polling thread(s). Spring Integration provides two different endpoint implementations to accommodate these two types of consumers. Therefore, the consumers themselves can simply implement the callback interface. When polling is required, the endpoint acts as a - "container" for the consumer instance. The benefit is similar to that of using a container for hosting - Message Driven Beans, but since these consumers are simply Spring-managed Objects running within an + container for the consumer instance. The benefit is similar to that of using a container for hosting + Message Driven Beans, but since these consumers are simply Spring-managed Objects running within an ApplicationContext, it more closely resembles Spring's own MessageListener containers. @@ -47,7 +47,7 @@ following chapters (Routers, Transformers, Splitters, Aggregators, Service Activators, etc). Those components each perform very different functionality with the Messages they handle, but the requirements for actually receiving a Message are the same, and the choice between polling and event-driven behavior is also the same. - Spring Integration provides two endpoint implementations that "host" these callback-based handlers and allow + Spring Integration provides two endpoint implementations that host these callback-based handlers and allow them to be connected to Message Channels. @@ -80,6 +80,12 @@ EventDrivenConsumer consumer = new EventDrivenConsumer(channel, exampleHandler); PollingConsumer consumer = new PollingConsumer(channel, exampleHandler); + + + For more information regarding Polling Consumers, please also read + as well as . + + There are many other configuration options for the Polling Consumer. For example, the trigger is a required property: @@ -89,7 +95,7 @@ consumer.setTrigger(new IntervalTrigger(30, TimeUnit.SECONDS)); Spring Integration currently provides two implementations of the Trigger interface: IntervalTrigger and CronTrigger. The IntervalTrigger is typically defined with a simple interval (in milliseconds), but - also supports an 'initialDelay' property and a boolean 'fixedRate' property (the default is false, i.e. + also supports an initialDelay property and a boolean fixedRate property (the default is false, i.e. fixed delay): IntervalTrigger trigger = new IntervalTrigger(1000); trigger.setInitialDelay(5000); @@ -107,15 +113,15 @@ consumer.setMaxMessagesPerPoll(10); consumer.setReceiveTimeout(5000); - The 'maxMessagesPerPoll' property specifies the maximum number of messages to receive within a given poll + The maxMessagesPerPoll property specifies the maximum number of messages to receive within a given poll operation. This means that the poller will continue calling receive() without waiting until either null is returned or that max is reached. For example, if a poller has a 10 second - interval trigger and a 'maxMessagesPerPoll' setting of 25, and it is polling a channel that has 100 messages + interval trigger and a maxMessagesPerPoll setting of 25, and it is polling a channel that has 100 messages in its queue, all 100 messages can be retrieved within 40 seconds. It grabs 25, waits 10 seconds, grabs the next 25, and so on. - The 'receiveTimeout' property specifies the amount of time the poller should wait if no messages are + The receiveTimeout property specifies the amount of time the poller should wait if no messages are available when it invokes the receive operation. For example, consider two options that seem similar on the surface but are actually quite different: the first has an interval trigger of 5 seconds and a receive timeout of 50 milliseconds while the second has an interval trigger of 50 milliseconds and a receive timeout @@ -123,7 +129,7 @@ consumer.setReceiveTimeout(5000); (if that message arrived immediately after one of its poll calls returned). On the other hand, the second configuration will never miss a message by more than 50 milliseconds. The difference is that the second option requires a thread to wait, but as a result it is able to respond much more quickly to arriving messages. - This technique, known as "long polling", can be used to emulate event-driven behavior on a polled source. + This technique, known as long polling, can be used to emulate event-driven behavior on a polled source. A Polling Consumer may also delegate to a Spring TaskExecutor, and it can @@ -159,22 +165,209 @@ consumer.setTransactionManager(txManager); Namespace Support Throughout the reference manual, you will see specific configuration examples for endpoint elements, such as - router, transformer, service-activator, and so on. Most of these will support an "input-channel" attribute and - many will support an "output-channel" attribute. After being parsed, these endpoint elements produce an instance + router, transformer, service-activator, and so on. Most of these will support an input-channel attribute and + many will support an output-channel attribute. After being parsed, these endpoint elements produce an instance of either the PollingConsumer or the - EventDrivenConsumer depending on the type of the "input-channel" that is + EventDrivenConsumer depending on the type of the input-channel that is referenced: PollableChannel or SubscribableChannel respectively. When the channel is pollable, then the polling behavior is determined based on the endpoint - element's "poller" sub-element and its attributes. For example, a simple interval-based poller with a 1-second interval would be + element's poller sub-element and its attributes. + + + Configuration + + Below you find a poller with all available configuration options: + + ]]> ]]> ]]>]]> + + + + + + Provides the ability to configure Pollers using Cron expressions. + The underlying implementation uses a + org.springframework.scheduling.support.CronTrigger. + + If this attribute is set, none of the following attributes + must be specified: fixed-delay, trigger, + fixed-rate, ref. + + + + + By setting this attribute to true, + it is possible to define exactly one (1) global default + poller. An exception is raised if more than one default + poller is defined in the application context. + + Any endpoints connected to a PollableChannel (PollingConsumer) + or any SourcePollingChannelAdapter that does not have any + explicitly configured poller will then use the global default + Poller. + Optional. Defaults to false. + + + + + Identifies the channel which error messages will be sent to if + a failure occurs in this poller's invocation. To completely + suppress Exceptions, provide a reference to the + nullChannel. Optional. + + + + + The fixed delay trigger uses a PeriodicTrigger + under the covers. If the time-unit attribute is + not used, the specified value is represented in milliseconds. + + If this attribute is set, none of the following attributes + must be specified: fixed-rate, trigger, + cron, ref. + + + + + The fixed rate trigger uses a PeriodicTrigger + under the covers. If the time-unit attribute is + not used the specified value is represented in milliseconds. + + If this attribute is set, none of the following attributes + must be specified: fixed-delay, trigger, + cron, ref. + + + + + The Id referring to the Poller's underlying bean-definition, + which is of type + org.springframework.integration.scheduling.PollerMetadata. + The id attribute is required for + a top-level poller element unless it is the default + poller (default="true"). + + + + + Please see + for more information. Optional. If + not specified the default values used depends on the context. + + If a PollingConsumer is used, this atribute + will default to -1. However, if a + SourcePollingChannelAdapter is used, + then the max-messages-per-poll attribute defaults to + 1. + + + + + Value is set on the underlying class PollerMetadata + Optional. If not specified it defaults + to 1000 (milliseconds). + + + + + Bean reference to another top-level poller. The ref + attribute must not be present on the top-level poller + element. + + However, if this attribute is set, none of the following attributes + must be specified: fixed-rate, trigger, + cron, fixed-deleay. + + + + + Provides the ability to reference a custom task executor. + Please see the section below titled TaskExecutor Support + for further information. Optional. + + + + + This attribute specifies the java.util.concurrent.TimeUnit + enum value on the underlying + org.springframework.scheduling.support.PeriodicTrigger. + Therefore, this attribute can ONLY + be used in combination with the fixed-delay + or fixed-rate attributes. If combined with + either cron or a trigger reference + attribute, it will cause a failure. + + + The minimal supported granularity for a + PeriodicTrigger is MILLISECONDS. + Therefore, the only available options are MILLISECONDS and + SECONDS. If this value is not provided, then any + fixed-delay or fixed-rate value + will be interpreted as MILLISECONDS by default. + + + Basically this enum provides a convenience for SECONDS-based + interval trigger values. For hourly, daily, and monthly + settings, consider using a cron trigger instead. + + + + + Reference to any spring configured bean which implements + the org.springframework.scheduling.Trigger + interface. + Optional. However, if this attribute + is set, none of the following attributes must be specified: + fixed-delay, fixed-rate, + cron, ref. + + + + + Allows to specify extra AOP Advices to handle additional + cross cutting concerns. Please see the section + below titled Transaction Support + for further information. Optional. + + + + + Pollers can be made transactional. Please see the section + below titled AOP Advice chains + for further information. Optional. + + + + + + + Examples + + + + For example, a simple interval-based poller with a 1-second interval would be configured like this: ]]> - As an alternative to 'fixed-rate' you can also use the 'fixed-delay' attribute. + As an alternative to fixed-rate you can also use the fixed-delay attribute. - For a poller based on a Cron expression, use the "cron" attribute instead: + For a poller based on a Cron expression, use the cron attribute instead: @@ -183,56 +376,78 @@ consumer.setTransactionManager(txManager); If the input channel is a PollableChannel, then the poller configuration is - required. Specifically, as mentioned above, the 'trigger' is a required property of the PollingConsumer class. - Therefore, if you omit the "poller" sub-element for a Polling Consumer endpoint's configuration, an Exception - may be thrown. The exception will also be thrown if you attempt to configure a poller on the element that is + required. Specifically, as mentioned above, the trigger is a required property of the PollingConsumer class. + Therefore, if you omit the poller sub-element for a Polling Consumer endpoint's configuration, an Exception + may be thrown. The exception will also be thrown if you attempt to configure a poller on the element that is connected to a non-pollable channel. - - It is also possible to create top-level pollers in which case only a "ref" is required: - - + + It is also possible to create top-level pollers in which case only a ref is required: + + + + ]]> + - The "ref" attribute is only allowed on the inner-poller definitions. Defining this attribute on a top-level - poller will result in a configuration exception thrown during initialization of the Application Context. + + The ref attribute is only allowed on the inner-poller definitions. Defining this attribute on a top-level + poller will result in a configuration exception thrown during initialization of the Application Context. + + + + Global Default Pollers + + + In fact, to simplify the configuration even further, you can define a global default poller. A single top-level poller within - an ApplicationContext may have the default attribute with a value of "true". In that case, any + an ApplicationContext may have the default attribute with a value of true. In that case, any endpoint with a PollableChannel for its input-channel that is defined within the same ApplicationContext and has - no explicitly configured 'poller' sub-element will use that default. + no explicitly configured poller sub-element will use that default. + - + ]]> + + + Transaction Support + Spring Integration also provides transaction support for the pollers so that each receive-and-forward operation can be performed as an atomic unit-of-work. To configure transactions for a poller, simply add the - <transactional/> sub-element. The attributes for this element should be familiar to anyone who has + <transactional/> sub-element. The attributes for this element should be familiar to anyone who has experience with Spring's Transaction management: - + + + -]]> +]]> + + For more information please refer to . + - AOP Advice chains + AOP Advice chains + - Since Spring transaction support depends on the Proxy mechanism  with TransactionInterceptor (AOP Advice) handling transactional - behavior of the message flow initiated by the poler, some times there is a need to provide extra Advice(s) to handle other - cross cutting behavior associated with the poller. For that poller defines an 'advice-chain' element allowing you to add + Since Spring transaction support depends on the Proxy mechanism  with TransactionInterceptor (AOP Advice) handling transactional + behavior of the message flow initiated by the poller, some times there is a need to provide extra Advice(s) to handle other + cross cutting behavior associated with the poller. For that poller defines an advice-chain element allowing you to add more advices - class that  implements MethodInterceptor interface..  @@ -243,32 +458,37 @@ consumer.setTransactionManager(txManager); -]]> -For more information on how to implement MethodInterceptor please refer to AOP sections of Spring -reference manual (section 7 and 8). Advice chain can also be applied on the poller that does not have +]]> +For more information on how to implement MethodInterceptor please refer to AOP sections of Spring +reference manual (section 8 and 9). Advice chain can also be applied on the poller that does not have any transaction configuration essentially allowing you to enhance the behavior of the message flow initiated by the poller. + + + TaskExecutor Support + + The polling threads may be executed by any instance of Spring's TaskExecutor - abstraction. This enables concurrency for an endpoint or group of endpoints. As of Spring 3.0, there is a "task" + abstraction. This enables concurrency for an endpoint or group of endpoints. As of Spring 3.0, there is a task namespace in the core Spring Framework, and its <executor/> element supports the creation of a simple thread pool executor. That element accepts attributes for common concurrency settings such as pool-size and queue-capacity. Configuring a thread-pooling executor can make a substantial difference in how the endpoint performs under load. These settings are available per-endpoint since the performance of an endpoint is one of the major factors to consider (the other major factor being the expected volume on the channel to which the endpoint subscribes). To enable - concurrency for a polling endpoint that is configured with the XML namespace support, provide the 'task-executor' + concurrency for a polling endpoint that is configured with the XML namespace support, provide the task-executor reference on its <poller/> element and then provide one or more of the properties shown below: - + ]]> - If no 'task-executor' is provided, the consumer's handler will be invoked in the caller's thread. Note that the - "caller" is usually the default TaskScheduler - (see ). Also, keep in mind that the 'task-executor' attribute can + If no task-executor is provided, the consumer's handler will be invoked in the caller's thread. Note that the + caller is usually the default TaskScheduler + (see ). Also, keep in mind that the task-executor attribute can provide a reference to any implementation of Spring's TaskExecutor interface by - specifying the bean name. The "executor" element above is simply provided for convenience. + specifying the bean name. The executor element above is simply provided for convenience. As mentioned in the background section for Polling Consumers above, you can also configure a Polling Consumer @@ -281,33 +501,88 @@ any transaction configuration essentially allowing you to enhance the behavior o participate. The following example demonstrates how a Polling Consumer will receive Messages nearly instantaneously. + output-channel="output"> - + ]]> Using this approach does not carry much overhead since internally it is nothing more then a timed-wait thread which does not require nearly as much CPU resource usage as a thrashing, infinite while loop for example. - + +
+ Change Polling Rate at Runtime + + When configuring Pollers with a fixed-delay or + fixed-rate attribute, the default implementation will use + a PeriodicTrigger instance. The + PeriodicTrigger is part of the Core Spring Framework + and it accepts the interval as a constructor + argument, only. Therefore it cannot be changed at runtime. + + + However, you can define your own implementation of the + org.springframework.scheduling.Trigger + interface. You could even use the PeriodicTrigger as a starting point. + Then, you can add a setter for the interval (period), or you could even + embed your own throttling logic within the trigger itself if desired. + The period property will be used with each call to + nextExecutionTime to schedule the next poll. + + To use this custom trigger within pollers, declare the bean defintion of + the custom Trigger in your application context and inject the dependency + into your Poller configuration using the trigger attribute, + which references the custom Trigger bean instance. + + You can now obtain a reference to the Trigger bean and the polling + interval can be changed between polls. + + + For an example, please see the Spring Integration Samples + project. It contains a sample called dynamic-poller, + which uses a custom Trigger and demonstrates the ability to change the polling + interval at runtime. + + + + https://github.com/SpringSource/spring-integration-samples/tree/master/intermediate + + + + The sample provides a custom Trigger which implements the + org.springframework.scheduling.Trigger + interface. The sample's Trigger is based on Spring's PeriodicTrigger + implementation. However, the fields of the custom trigger are not final + and the properties have explicit getters and setters, allowing to dynamically + change the polling period at runtime. + + + It is important to note, though, that because the Trigger method is + nextExecutionTime(), any changes to a dynamic trigger + will not take effect until the next poll, based on the existing configuration. + It is not possible to force a trigger to fire before it's currently + configured next execution time. + +
+
Payload Type Conversion - Throughout the reference manual, you will also see specific configuration and implementation examples of various endpoints - which can accept a Message or any arbitrary Object as an input parameter. In the case of an Object, such a parameter will - be mapped to a Message payload or part of the payload or header (when using the Spring Expression Language). However there - are times when the type of input parameter of the endpoint method does not match the type of the payload or its part. - In this scenario we need to perform type conversion. Spring Integration provides a convenient way for registering type + Throughout the reference manual, you will also see specific configuration and implementation examples of various endpoints + which can accept a Message or any arbitrary Object as an input parameter. In the case of an Object, such a parameter will + be mapped to a Message payload or part of the payload or header (when using the Spring Expression Language). However there + are times when the type of input parameter of the endpoint method does not match the type of the payload or its part. + In this scenario we need to perform type conversion. Spring Integration provides a convenient way for registering type converters (using the Spring 3.x ConversionService) within its own instance of a conversion service bean named integrationConversionService. That bean is automatically created as soon as the first converter is defined using the Spring Integration namespace support. To register a Converter all you need is to implement - org.springframework.core.convert.converter.Converter and define it via + org.springframework.core.convert.converter.Converter and define it via convenient namespace support: ]]> - + or as an inner bean: @@ -318,9 +593,9 @@ any transaction configuration essentially allowing you to enhance the behavior o
Asynchronous polling - If you want the polling to be asynchronous, a Poller can optionally specify a 'task-executor' attribute - pointing to an existing instance of any TaskExecutor bean - (Spring 3.0 provides a convenient namespace configuration via the task namespace). However, there are certain things + If you want the polling to be asynchronous, a Poller can optionally specify a task-executor attribute + pointing to an existing instance of any TaskExecutor bean + (Spring 3.0 provides a convenient namespace configuration via the task namespace). However, there are certain things you must understand when configuring a Poller with a TaskExecutor.  @@ -328,21 +603,21 @@ any transaction configuration essentially allowing you to enhance the behavior o and they both have to be in tune with each other otherwise you might end up creating an artificial memory leak. - Let's look at the following configuration provided by one of the users on the Spring Integration + Let's look at the following configuration provided by one of the users on the Spring Integration forum (http://forum.springsource.org/showthread.php?t=94519): - + ]]> - + The above configuration demonstrates one of those out of tune configurations. - The poller keeps scheduling new tasks even though all the threads are blocked waiting for either a new message to arrive, - or the timeout to expire. Given that there are 20 threads executing tasks with a 5 second timeout, they will be executed - at a rate of 4 per second (5000/20 = 250ms). But, new tasks are being scheduled at a rate of 20 per second, so the internal + The poller keeps scheduling new tasks even though all the threads are blocked waiting for either a new message to arrive, + or the timeout to expire. Given that there are 20 threads executing tasks with a 5 second timeout, they will be executed + at a rate of 4 per second (5000/20 = 250ms). But, new tasks are being scheduled at a rate of 20 per second, so the internal queue in the task executor will grow at a rate of 16 per second (while the process is idle), so we essentially have a memory leak. diff --git a/src/reference/docbook/messaging-channels.xml b/src/reference/docbook/messaging-channels.xml index 089245c31f..dc90004333 100644 --- a/src/reference/docbook/messaging-channels.xml +++ b/src/reference/docbook/messaging-channels.xml @@ -5,6 +5,7 @@ Messaging Channels + diff --git a/src/reference/docbook/polling-consumer.xml b/src/reference/docbook/polling-consumer.xml new file mode 100644 index 0000000000..ee1e68499a --- /dev/null +++ b/src/reference/docbook/polling-consumer.xml @@ -0,0 +1,71 @@ + +
+ Poller (Polling Consumer) + + When Message Endpoints (Channel Adapters) are connected to channels and + instantiated, they produce one of the following 2 instances: + + + PollingConsumer + EventDrivenConsumer + + + The actual implementation depends on which type of channel these Endpoints + are connected to. A channel adapter connected to a channel that implements + the org.springframework.integration.core.SubscribableChannel + interface will produce an instance of EventDrivenConsumer. + On the other hand, a channel adapter connected to a channel that implements the + org.springframework.integration.core.PollableChannel + interface (e.g. a QueueChannel) will produce an instance of PollingConsumer. + + + Polling Consumers allow Spring Integration components to actively poll for + Messages, rather than to process Messages in an event-driven manner. + + + They represent a critical cross cutting concern in many + messaging scenarios. In Spring Integration, Polling Consumers are based + on the pattern with the same name, which is described in the book + "Enterprise Integration Patterns" by Gregor Hohpe and Bobby Woolf. You + can find a description of the pattern on the book's website at: + + + + http://www.enterpriseintegrationpatterns.com/PollingConsumer.html + + + + Furthermore, in Spring Integration a second variation of the Polling Consumer + pattern exists. When Inbound Channel Adapters are being used, these adapters + are often wrapped by a SourcePollingChannelAdapter. + For example, when retrieving messages from a remote FTP Server location, + the adapter described in + is configured with a poller to retrieve messages periodically. + So, when components are configured with Pollers, the resulting instances are + of one of the following types: + + + PollingConsumer + SourcePollingChannelAdapter + + + This means, Pollers are used in both inbound and outbound messaging scenarios. + Here are some use-cases that illustrate the scenarios in which Pollers are + used: + + + Polling certain external systems such as FTP Servers, Databases, Web Services + Polling internal (pollable) Message Channels + Polling internal services (E.g. repeatedly execute methods on a Java class) + + + This chapter is meant to only give a high-level overview regarding Polling Consumers + and how they fit into the concept of message channels - and + channel adapters - + . For more in-depth information regarding + Messaging Endpoints in general and Polling Consumers in particular, please see + . + + +