Alternative way of defining Graph Stages #121
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Preconditions.
Generally, the processing of the received element from the inlet or the event from the timer results in the writing of the resulting elements to one or more outlets. The event from the inlet or timer should not be processed until every outlet into which the writing can be made, became ready to be written, or its buffer will allow the acceptance of new elements.
Using of low-level pull/grab/push functions to control back-pressure is fraught with errors and complicates the application logic. Also, Akka Streams does not provide today the possibility of specifying a buffer with OverflowStrategy for the outlet in GraphStage with arbitrary Shape.
Decision.
The idea is to describe the relationships between inlets, events from the timer and outlets. For each link, the buffer for outgoing elements and OverflowStrategy can be specified. An element from the inlet or event from the timer enters the processing only when the outlet is available for writing for each link, or OverflowStrategy for the buffer allows you to receive at least one element. If there are no connections for the incoming port or timer, the element from the inlet or event from the timer will be processed immediately.
If the outlet is linked to several inlets, items for writing to the outlet are accumulated in different buffers belonging to different links. When the outlet becomes available for writing, the elements from the buffers will be written in the same order as they were pushed.
Links can be added/deleted at any time. Deleting a link with the outlet does not delete the buffer until it is freed.
Sometimes the business logic of an application requires more than one item to be written to the outlet at same time. In this case, the element is placed to the buffer. This is allowed, but the application should not abuse this possibility.
LinkedLogics class implements the specified logic. LinkedLogics inherits GraphStageLogic, but it is a final class, and can not be inherited by the application. Low-level pull/grab/push functions with access "protected" are not visible from the outside, which completely excludes their use by the application. LinkedLogics represents a new level of management of the back pressure policy within GraphStage.
Linking.
For each inlet in the shape, InputLogic object must be created and added to the LinkedLogics.
The links with the outlets and the handler of the received elements are defined inside the InputLogic.
Once LinkedLogic is started, new links can also be added.
When the link becomes unnecessary, it can be deleted by calling LogicLink.remove()
Using timers.
TimerLinkedLogics except linking inlets and outlets allows to create timers and associate them with outlets. TimerLinkedLogics inherits TimerGraphStageLogic and is the final class.
To start a timer that periodically runs through a time interval, PeriodicallyTimerLogic is created and added to the TimerLinkedLogics.
The PeriodicallyTimerLogic constructor can specify an initial delay and a time interval.
Just like in the case of InputLogic, you can add and remove links in the process.
The call to TimerLogic .cancel() terminates the timer and removes TimerLogic from TimerLinkedLogics.
Manual control of back pressure.
Application logic may require you to set back pressure on the inlet regardless of the availability of outlets. A special Stopper link creates an eternal back pressure on the incoming port:
var stopper = logic.linkStopper()
To open the input, we need to remove Stopper:
stopper.remove()