Processor Behavior Annotations
When creating a Processor, the developer is able to provide hints to the framework about how to utilize the Processor most effectively. This is done by applying annotations to the Processor's class. The annotations that can be applied to a Processor exist in three sub-packages of
org.apache.nifi.annotations. Those in the
documentation sub-package are used to provide documentation to the user. Those in the
lifecycle sub-package instruct the framework which methods should be called on the Processor in order to respond to the appropriate life-cycle events. Those in the
behavior package help the framework understand how to interact with the Processor in terms of scheduling and general behavior.
The following annotations from the
org.apache.nifi.annotations.behavior package can be used to modify how the framework will handle your Processor:
EventDriven: Instructs the framework that the Processor can be scheduled using the Event-Driven scheduling strategy. This strategy is still experimental at this point, but can result in reduced resource utilization on dataflows that do not handle extremely high data rates.
SideEffectFree: Indicates that the Processor does not have any side effects external to NiFi. As a result, the framework is free to invoke the Processor many times with the same input without causing any unexpected results to occur. This implies idempotent behavior. This can be used by the framework to improve efficiency by performing actions such as transferring a ProcessSession from one Processor to another, such that if a problem occurs many Processors' actions can be rolled back and performed again.
SupportsBatching: This annotation indicates that it is okay for the framework to batch together multiple ProcessSession commits into a single commit. If this annotation is present, the user will be able to choose whether they prefer high throughput or lower latency in the Processor's Scheduling tab. This annotation should be applied to most Processors, but it comes with a caveat: if the Processor calls
ProcessSession.commit, there is no guarantee that the data has been safely stored in NiFi's Content, FlowFile, and Provenance Repositories. As a result, it is not appropriate for those Processors that receive data from an external source, commit the session, and then delete the remote data or confirm a transaction with a remote resource.
TriggerSerially: When this annotation is present, the framework will not allow the user to schedule more than one concurrent thread to execute the
onTriggermethod at a time. Instead, the number of thread ("Concurrent Tasks") will always be set to
1. This does not, however, mean that the Processor does not have to be thread-safe, as the thread that is executing
onTriggermay change between invocations.
PrimaryNodeOnly: Apache NiFi, when clustered, offers two modes of execution for Processors: "Primary Node" and "All Nodes". Although running in all the nodes offers better parallelism, some Processors are known to cause unintended behaviors when run in multiple nodes. For instance, some Processors list or read files from remote filesystems. If such Processors are scheduled to run on "All Nodes", it will cause unnecessary duplication and even errors. Such Processors should use this annotation. Applying this annotation will restrict the Processor to run only on the "Primary Node".
TriggerWhenAnyDestinationAvailable: By default, NiFi will not schedule a Processor to run if any of its outbound queues is full. This allows back-pressure to be applied all the way a chain of Processors. However, some Processors may need to run even if one of the outbound queues is full. This annotations indicates that the Processor should run if any Relationship is "available." A Relationship is said to be "available" if none of the connections that use that Relationship is full. For example, the DistributeLoad Processor makes use of this annotation. If the "round robin" scheduling strategy is used, the Processor will not run if any outbound queue is full. However, if the "next available" scheduling strategy is used, the Processor will run if any Relationship at all is available and will route FlowFiles only to those relationships that are available.
TriggerWhenEmpty: The default behavior is to trigger a Processor to run only if its input queue has at least one FlowFile or if the Processor has no input queues (which is typical of a "source" Processor). Applying this annotation will cause the framework to ignore the size of the input queues and trigger the Processor regardless of whether or not there is any data on an input queue. This is useful, for example, if the Processor needs to be triggered to run periodically to time out a network connection.
InputRequirement: By default, all Processors will allow users to create incoming connections for the Processor, but if the user does not create an incoming connection, the Processor is still valid and can be scheduled to run. For Processors that are expected to be used as a "Source Processor," though, this can be confusing to the user, and the user may attempt to send FlowFiles to that Processor, only for the FlowFiles to queue up without being processed. Conversely, if the Processor expects incoming FlowFiles but does not have an input queue, the Processor will be scheduled to run but will perform no work, as it will receive no FlowFile, and this leads to confusion as well. As a result, we can use the
@InputRequirementannotation and provide it a value of
INPUT_FORBIDDEN. This provides information to the framework about when the Processor should be made invalid, or whether or not the user should even be able to draw a Connection to the Processor. For instance, if a Processor is annotated with
InputRequirement(Requirement.INPUT_FORBIDDEN), then the user will not even be able to create a Connection with that Processor as the destination.