Skip to content

Add page abount flow control #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions get_started_with_membrane/06_flow_control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Flow Control

Once we have linked the elements together, there comes a moment when they can start sending buffers through the pads. However, how to control the flow of buffers between elements?

Membrane solves this problem using its own backpressure mechanism and demands.

## Types of `flow_control`

When defining a pad od an element, you can pass one of 3 values in the `flow_control` field: `auto`, `push`, or `manual`. They determine how the backpressure mechanism works on the pad they relate to.

- Input pad with `flow_control: :push` - an element with such a pad must always be ready to receive a new buffer on that pad. The output pad linked with such an input pad must also have `flow control` set to `:push`. It is not advised to use `flow_control: :push` in input pads, as it makes them prone to overflow.

- Output pad with `flow_control: :push` - the element decides for itself when to send how many buffers via a given pad.

- Input pad with `flow_control: :manual` - the element directly, using the `demand` action, requests how much data it wants to receive from this pad. Membrane guarantees that more data will never come to the input pad than was demanded.

- Output pad with `flow_control: :manual` - the element gets the information, through the `c:Membrane.Element.WithOutputPads.handle_demand/5` callback, how much data a specific output pad needs. An element having an output pad with `flow_control: :manual` is obligated to satisfy the demand on it.

- Input pad with `flow_control: :auto` - unlike in manual demands, the element doesn't have to directly specify the demand value on the input pad to receive buffers on it. In `:auto` `flow control`, the framework will manage the demand value itself. In the case of Sources and Endpoints, it will make sure that the demand on the input pad is positive as long as the number of buffers waiting for processing in the mailbox is not too large. In the case of filters, Membrane will take care of a positive demand under one additional condition - the demand value on all output pads with `flow_control: :auto` of this element must also be positive.

- Output pad with `flow_control: :auto` - an auto output pad does not require from the element to implement the `handle_demand` callback. The demand value on this pad only matters when the framework itself calculates the value of the auto demand on the input pads. The only type of Membrane Element that can have output pads with `flow_control: :auto` is a `Membrane.Filter`.

`flow_control: :manual` is useful in cases, when element wants to get a specific amount of data on each pad (e.g. to satisfy demand on 1 buffer on pad `:output`, element need 1 buffer from pad `:input_a`, 10 buffers from pad `:input_b` and 100 bytes from pad `:input_c`). Comparing to `flow_control: :auto`, `flow_control: :manual` can solve a broader class of problems, but, on the other hand, it requires more code in your element and is less performant.

`flow_control: :auto` is the best solution, when you want to provide a backpressure mechanism, but your element has only one input pad or it doesn't care about the proportion of the amount of data incoming on each input pad. A good example might be a pipeline made of filters linked one after the other, with a sink or a source on each end. In such a case, using `flow_control: :auto` in filters would ensure, that the pipeline would adapt its processing pace to the slowest element, without the necessity to implement `c:Membrane.Element.WithOutputPads.handle_demand/5` in every element. Additionally, the whole pipeline will be faster, because of the lack of performance overhead caused by `flow_control: :manual`.

## Linking pads with different `flow_control`

Two pads with the same type of `flow_control` can always be linked together. `flow_control: auto` can also always be linked with `flow_control: manual`. However, the situation becomes complicated when we try to link two pads with different types of `flow_control`, where one of them has `flow_control: push`.

When the input pad has `flow_control: push`, the output pad linked to it must also have `flow_control: push`. An attempt to link different type of an output pad will cause an error to be thrown.

Output pads with `flow_control: push` can be linked with input pads having `flow control` `:auto` or `:manual`. The demand value on such an input pad does not affect the behavior of the element with the push output pad.

When an element with a push output pad sends amount of data, that exceeds demands on the input pad, when input pad `flow_control` is:
- `manual`, these buffers will wait in line until the element raises the demand on its input by returning the `demand` action.
- `auto`, these buffers will be processed, and the demand value on the input pad will drop below zero.

```elixir
get_child(:mixer)
|> via_in(:input, toilet_capacity: 500)
|> get_child(:sink)
```
5 changes: 3 additions & 2 deletions get_started_with_membrane/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ graphicPath: assets/images/Illo_get_started.png
| 3 | Elements | 03_elements.md |
| 4 | Bins | 04_bins.md |
| 5 | Pads & linking | 05_pads_and_linking.md |
| 6 | Observability & logging | 06_observability_and_logging.md |
| 7 | Native code integration | 07_native_code_integration.md |
| 6 | Flow control | 06_flow_control.md |
| 7 | Observability & logging | 07_observability_and_logging.md |
| 8 | Native code integration | 08_native_code_integration.md |