So, continuing to dive deep into go, and there are many new packages, which I told you this
morning about if you missed a watch a video, and one of them was synchest, and it looked
to me like a very interesting package, and then we're not just spontaneously offered to
come back to force them after five years, six, only, what year did you last present in my
bedroom?
In my bedroom?
Yes?
Okay.
It looks like yesterday, and she was so great with her last apartment, was it about controversial
topics about go?
Was it that one?
Yeah.
Go as object oriented.
Yes, that one.
And she was so great that I just invited her back, so I'm very proud of her
class for Rona.
Thank you.
Hi.
So, as Marty said, my name is Rona, and I love introducing myself.
I also give go workshops around various topics, and there's a pipeline usually to
my talks, not my workshops, my talks.
And it works something like this.
So, I prepare for a workshop, something happens, and then I give a talk.
And yeah, so what I'm trying to say by this is this is not a promotion to my upcoming workshop,
which I'm giving with Jonathan Amsterdam, which I'm giving with Jonathan Amsterdam, a number
of the go team.
And this is a great opportunity to thank him for helping me put together this talk.
And yeah, it's important to say this because that would be wrong and super confusing for
everyone.
But it really is just a backstory of this talk, so not a promotion.
So what happened?
What happened that I'm giving this talk?
Well, I need to consider these two functions.
So we have these two functions.
One is, do you know that luck by the way, back row, if you cannot hear me, do something
like this?
Well, so that means that you cannot hear me because you just did the thing, interesting,
very interesting.
Okay.
I see you, so I need you to consider these two functions, one is, and Martia, one is
do know that luck, that just logs that do know that luck was in vote.
And one is do that luck, which logs that it was in vote, and that locks.
It that locks because we create a channel, and then we try to read from that channel in
this and there are no messages in the channel, so it's just going to block forever, which
is fine.
Now, let's create a test that runs both of these functions into different go routines using
a weight group.
So since do that luck, that locks, weight group weight is going to just wait forever.
So far, so good.
I'm probably not telling you anything that you didn't know already.
So we run this test with a timeout, and it will result in something like this, panic this
time down, after 100 milliseconds, and of course, if we didn't provide a timeout, it would
just thank forever until terminated.
So let's fix this test by replacing the calls from to do that luck, instead we're going
to call, do know that luck, it's like do no wrong, yeah.
And it runs, and it passes, and everything is good in life, let's make it more interesting.
Let's have do no dead luck, start a new go routine that calls do dead luck.
Now I have what's called a go routine leak, but my test still passes.
Delivey?
Or more generally, like, for me, I don't know about your applications, but my look something
like, you know, like, generate a bunch of, you know, go routines, do some stuff, everything
is out of control, I never said it was good at it.
They launch a bunch of more go routines, and all of my tests pass, so like, yeah, anyway, so
I spoke to John, and it was like, so what is the right way to teach people, because
I was going to basically teach people how to profile, like, detect this stuff, and then
you said, when I watched the stintest talk, just use stintest.
Now, here's a problem with stintest, I cannot pronounce stintest.
So we are, we are all for our great start, but anyways, testing slash stintest package
was introduced into go 125, just recently kind of sort of, and it runs test inside a bubble,
and a bubble has a few features that are pretty, pretty cool.
I also live in a bubble, so I know something about that.
And yeah, basically, the bubble knows about the go routines that were created within it,
she is very useful, because I can do something like this, this very naive thing here, that's
all go routines, finish stintest, and I'm just going to create here, like, launch here
two calls to go, do whatever in this case, do no deadlock, which we know deadlocks in
a different go routine.
And there is no weight groups or anything, and it just fails, and it fails immediately.
Jonathan had a point.
That is the right way to do this.
So yeah, I could stop here, and basically let's just, but there is more to cover.
So what do we see here?
We see here that, even though I didn't use any weight group, I didn't track my go routines,
and I'm just letting you let go, whatever, and something just got stuck, and didn't return
the bubble knew about it, or when the test function finished, we basically had some
form of tracking of what is happening, and the deadlock was detected.
We didn't have to wait for a timeout.
Unfortunately, by the way, that's not always going to be the case, even with stintest.
And yeah, and everything, you know, failed quite quickly, so they say that time is money.
I say they say that time is money, because that has not been my experience.
So, the features of the bubble.
So what is this dark magic?
Well, the bubble waits for Goretyn's credit inside of it to finish, that's kind of, you know,
obvious.
Quoting from the docs, tests waits for all Goretyn's in the bubble to exit before
resuming, if the Goretyn's in the bubble become deadlocked, the test fails.
Now there are caveats, though, to this, and we need to learn a new term that's durability
blocked.
So it's not just blocked, it's durability blocked.
And a Goretyn is durability blocked when it, and I'm quoting here from the blog post about
stintest, when it can only be unlocked by another Goretyn in the bubble, exactly.
The list of durability blocked operations are, or is a sender receive on a new channel, a sender
received or receive blocked on a channel created within the same bubble.
The select statement where every case is durability blocking, so yeah, that's a recursion.
I'm testing you.
Yes, durability blocked, test case that is durability blocked, there we go.
Time sleep, sync, condition, weight, and, of course, weight group weight.
So far so good.
However, there are blocking operations that are not durability blocked, for instance, and
a very, very important one is the I.O.
So I'm going to quote Damian Neil, Neil's talk about this, now he is the one who is responsible
for all of this magic, so he should know.
Channels, so basically, not durability blocked are channels that are created outside the bubble
that makes sense.
I.O., Cisco, Sigo, and pretty much anything that is not go.
And unfortunately, also mutexes, which is kind of, to be honest, plus you, mutexes, which
is kind of less you, which is, this was hard felt like, I see, I also have allergies,
and it's winter, so it's a bit disappointing, really, like the thing about the mutexes,
there is an explanation why didn't go in, essentially like it was hard to not hurt the
performance as a mutexes that are supposed to be quite fast to do this.
So yeah, so unfortunately for now, mutexes are not, you'reably blocking, and that's kind
of important, and I'll show you in a second what that means.
So, for example, okay, let's talk about I.O. first, so for example, we have this example
of a test of go, listen and serve, whatever, yes, I didn't test, I didn't check my errors,
I don't know, I told you, not very good at this, anyways, so I create a guarantee in a
white form for some I.O. the bubble cannot know if I.O. is coming or not, cannot really
fail this test, that makes sense, you know, you're going to have to provide a timeout,
essentially, to kill this test.
So yeah, so in this particular case, it is not very useful, that being said, if you have
a server and you have, you know, you're testing the raceful shutdown, it is amazing.
So we still need a timeout.
Now let's talk about mutexes, because that kind of, that is kind of painful to be honest.
So I created here a function called due deadlock with mutex, guys in the back still can
hear me, right?
Well now they're not doing the things, I don't know, so, anyways, I did, I basically try
to lock mutex twice, obviously the second time is just not, it's just going to hang forever
or until terminated.
So yeah, so I try to run this within a test and it's just going to hang and it needs a
timeout.
So far, so good or bad, if you decide.
So yeah, so just always run the synthesis with a timeout, I mean technically like always
run test for a timeout, just makes sense to be safe, you know.
Now stick this also comes with, I said it correctly, yeah, with a weight function and the
way that Damien explains it, it's kind of like running runtime goes cad in a four loop until
kind of can't make any progress anymore.
So it's yielding back the CPU, like, you know, over and over and over and over again
until everything is kind of run.
And the way that the documentation explains it is weight blocks until every go routine
within the current bubble, other than the current go routine is door of the blocked, which
we already covered the definition of door of the block, super easy stuff.
So consider this example, we start a go routine with a worker that iterates over a channel,
that channel has a buffer for one message.
So right into it once is not blocking.
I have a variable process, which is an integer and on every read from the channel, we place
the red integer inside process.
So essentially, we read from the channel, we put it in process.
We write 42 to the channel and would like to see that process is set to 42 or fill the
test.
However, since the channel has a buffer, there is no guarantee that what we wrote to the
channel has already been read, that would be an unbuffer channel.
So we need to sync here, something.
Well, sync test weights for the rescue.
That's what it does here without it.
We're going to have a race.
And also, so this test is a flaky in the flaky sense that 99% of the time it will fail
is sometimes succeed, not the other way around, not like most of your CI.
So yeah, so if we run it, this is what it's going to look like.
Okay, impressive stuff.
So that's sync weight.
But that's not all.
Sync test comes with time travel.
You can travel back into how who here has been born after a January 1, 2000.
Yeah, so welcome to the year 2000.
This is going to be first time for you.
The rest of us, yay.
Okay.
So yeah, every bubble starts with a start time of January 1st, like midnight,
January midnight, UTC, January 1st, 2000, white, okay, welcome to white, okay.
And yeah, if you're older, obviously, welcome back.
In this code, I start a sync test and I log the time and then in a loop,
I sleep for a second and I log the time.
Do this three times.
And this is what the result would look like.
So this is kind of fun.
So first, you will notice that this test did not take three seconds to execute.
That is because time has a fake clock inside the bubble.
Yeah.
And you will notice also that the time is white, okay.
Now this, I really appreciate this is excellent trolling here me out.
I don't know why they selected this date.
But they do know that forensic anthropologists of the future are going to look at this material
and say, well, they knew about time travel.
I think that they could go back farther than 2000.
Brilliant stuff.
Brilliant.
Anyways.
So more about stuff that you can do with time manipulation.
So here is some time sensitivity of functionality.
I created a function, retry.
It takes a function that returns in error.
It also takes how many times you're supposed to retry this thing.
And in interval, like how long you're going to wait between those retries.
And yeah, and it's kind of like what you would expect for range.
And if there was an error, sleep, and then you know, do it again.
And times of Allah.
You can read code.
I know you can.
You can.
Um.
So yeah, finally, if whenever succeeded, we're turning error now.
Our test calls retry with n equals 3 in a way time between retries of 10 seconds.
Because who knows, maybe, you know, this function that we're calling here, particularly.
It just returns errors new, but maybe we're just calling an external resource.
And that's, you know, we don't want to bombard it.
So you're not going to wait 30 seconds for this to return.
But here, it's kind of fun.
It's not going to take 30 seconds to run a test.
No.
Sorry.
First and foremost, the test retry without sync test.
Um, it's going to look something like this.
So, uh, create a function.
10 seconds, retry time sleep.
30 seconds.
Uh, we have some channel here that we close for signaling to know that, you know,
uh, retry is actually finished.
Um, and so on and so forth.
And then what's in test?
And it takes 30 seconds as you can see.
Which is.
I was sitting a while in front of the computer.
I didn't just write this number there.
Right, this way.
Um, so with sync test, it looks like this.
So, first of all, you will see, you will notice that it's shorter.
Uh, we use sync test weight for the syncing to prevent the race.
Uh, we just sleep 30 seconds, which is effects 30 seconds.
Again, at the end of the 30 seconds, so like in the meantime,
sleep, uh, for 10 seconds that happens three times was actually invoked.
All of this was done for you.
We just ran it.
And yeah, this is how long it actually took.
So, 300 milliseconds.
This is quite nice.
Um, so here are the stuff that I was able to test with, with all of this.
Um, I was able to test race full shutdown.
I was able to test, uh, a cash with, uh, TTL.
So time to live with, like, entries that expire.
Uh, and then I looked at that.
And I was like, okay, I want to make it a little bit more complex.
So I created a server, a server that, uh, handle session.
And those sessions have time out.
And then I created a recording, a recording that maintain the times.
And that maintains the timestamps of those requests that are made to the server.
So I have requests through the server and their timestamps.
And then I sleep between them.
And therefore, when I run this recording, I don't write out of memory.
Just quite cool.
Also, so they may actually set any stock that time only moves forward.
Now, I, I'm going to show you in a second that he actually built a time machine,
where you can have time going backwards, but not further than 2000.
Um, and, uh, yeah, so something that I, I was thinking about,
I was thinking about was like, is there a reason why I would use two bubbles?
Like, essentially, and reset the time, uh, and have, uh, and have,
and what I figured out was, I'm sure we have these services that communicate with each other.
Maybe their clocks are in sync.
So you can actually simulate time going backwards forwards,
whatever you need to within a test.
Just, you know, test your protocols etc.
So that's pretty cool.
Um, and, uh, yeah, and those are just, you know,
uh, these, uh, fun examples that I came up with,
um, you probably have your own ideas of what you can do with this.
Uh, thank you very much, and now I will finish with a demo of time going backwards.
Well, I would finish with a demo if I could move this here.
I don't know where I'm going.
Is this not, uh, where is the other screen?
Do you guys see anything?
No, okay.
One day I'll get there.
There it go.
Look at time going backwards.
With the time now.
Thank you very, very much. You were great.