- Now let's look at another pattern
that can leverage a buffer channel,
and this is the drop pattern.
Drop patterns are very, very powerful patterns.
Again, helping us reduce back pressure
when things are going bad.
They can help us actually identify when things are going bad
and reduce back pressure.
Good example of a drop pattern could be
if you were writing a DNS server.
What are the chances of that DNS server getting attacked?
Nah, it's never gonna happen, right?
Yeah, it's gonna get attacked all day long.
The whole idea of that DNS server attack
is to flood the server with so many requests
that it drowns itself trying to process everything.
So you can't.
What the drop pattern tries to identify
is what our capacity is, right?
What is the maximum number of pending anything,
requests, tasks, that we can take in
before we have to say no.
Look, it's easy to say yes.
You gotta learn how to say no in life.
And at some point you have to know
what is your maximum capacity, and then just say no.
And a drop pattern, we say, I'm sorry I can't
handle your requests.
I'm at capacity, I'm not going to go down for you.
It's going to take integration tests and load testing,
usually, to figure out what your capacity is.
And it might also be based on how much memory you have,
and your CPU capacity, could be dynamic
depending on the system that you're running on.
But drop patterns are very, very powerful.
They help us identify failures quickly,
they help us stop the bleeding.
And then, they help us move forward again,
when the bleeding has been,
or when that wound has been healed.
Let's take a look at a basic drop pattern.
So, here we are, got a constant of five.
And this time what I'm going to do,
is make a buffered channel of five.
This buffered channel of five is our capacity.
What we're saying is once we have at least five
pending tasks waiting in our buffer here,
we're at capacity.
We're not going to go to six.
At that point, we're just going to drop
the work on the floor.
We're not going to take it.
Taking anymore is too much risk.
Now, if you look at on line 194,
here we are again in our main,
we've created our buffer channel of five.
That's our buffer channel of five.
That's our capacity.
We go ahead and we launch a Go routine.
Now, this could have easily been
a pool of Go routines, right?
But, and we're just keeping the code simple,
understand this could be one or many Go routines.
And there we are, again, on the four range.
We are receiving on line 195,
receiving from this buffer.
In other words, what we're going to be doing
on this one Go routine,
is we're going to be in our receive, right?
We're going to be in our channel receive.
Where the idea here is, here's our channel,
receive that.
As soon as data comes in to the buffer,
then we want the corresponding,
right, it's a receive.
So, once data comes into the buffer,
the send happens before the receive,
but once we see it,
then we're going to want to pull it out.
More data comes in, we're going to pull it out.
But this Go routine's only operating on one task at a time.
So, once we receive it, we process it.
We come back, we pull any more data.
If there isn't any data, then we block on the channel
receive, waiting, right?
That's the floor range.
Eventually, we close the channel
and the floor range terminates.
So, here's the idea, maybe we're reading some
network device, right?
Let's do that right there on line 201, for a second.
Maybe what we're doing now that we've set this up,
is we're here, and you know, maybe we're reading.
We're reading, sorry reading,
some sort of network.
And as we pull data out of the network,
we just start moving it, right?
We send it into our buffer.
But once this hits five,
we know a couple things.
Once this hits five we can't do this anymore.
Now, this data has to go from here,
and we have to drop it.
We can't add it, we drop it.
We're not going to block.
At the same time, it could mean that this Go routine
isn't running fast enough.
It could mean that this Go routine has a problem right now.
It's not coming back into the receive.
And so, the health of our system
is measured by our capacity.
If this is working fast enough,
then this buffer never gets full.
But if something bad happens, and the buffer gets full,
we no longer block, we don't take blocking latencies,
we drop.
Now, in order for this to work, we got to be able
to identify when we're full, without fully blocking.
And I want you to see the use of the select statement here.
So, I'm in my loop here, where I'm going to be simulating
20 network reads of data,
and I'm in a select.
Now, what's powerful about the select statement,
is it allows a single Go routine,
to handle multiple channel operations,
whether they're sends or receives,
at exactly the same time.
So you can create event loops here.
This is also how we're going to do cancellation
and deadlines,
and a drop pattern is very much like a cancellation.
So, look at what we do here.
I've got the select, and we've got our first case,
which is the channel send.
Again, the idea is we've read some data off the network
and on line 203 we're trying to perform this send.
We're trying to perform the send.
Now, if we can perform the send,
if we can perform this send, guess what?
The data gets in the buffer, life is good,
we go back to 201 in the top of the loop
and we get the next piece of data.
We try to perform the send again.
If the send is not going to block,
because there's room in the buffer, brilliant.
But what if that send is going to block
because we are at capacity.
Remember, if all five,
if there's five pending tasks in here,
then it's going to block.
We don't want that latency cost, right?
So, that's where the default comes in.
What the default says is,
if the send is going to block, guess what?
Don't block, move on.
Move on.
And we're, basically, now going to decide
what we're going to do with this data
we read off the network.
We're going to somehow drop it.
Maybe send back a 500,
maybe send back that we couldn't do it.
We're not going to take latency costs.
We're not going to create back pressure
against this channel.
Either we can do it, or we can't do it.
And when we can do it, brilliant, let's get it done.
When we can't do it, it's a really strong indication
that we have a problem in our server.
So, drop patterns are very, very important.
They're very clean ways of identifying
when we're at capacity.
When we're having potential problems,
they help reduce back pressure.
Because this isn't necessarily time out reduction,
it's literally, capacity reduction.
And again, we're using the buffered channel
to help us identify when there's failure.
And, eventually, when this buffer begins
to be processed again,
then we know that life is good again.
So drop patterns are very, very, very powerful patterns.
And another, kind of, core high-level pattern
along with the pooling, along with the fan outs,
that you'll be using to handle different types
of orchestration in your software.