This video demonstrates a real senior Go interview where the candidate reviews a payment processing worker system, identifying critical bugs including missing SELECT FOR UPDATE SKIP LOCKED for concurrent record processing, N+1 query problems requiring batching, Outbox Pattern implementation for reliable message delivery, and deadlock prevention through application-level locking with status fields and timeout mechanisms. The interview covers database indexing strategies, worker pool parallelization using goroutines and channels, and proper testing approaches with table-driven tests and mocks.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Golang Live Interview: Senior в Uzum, ex-Яндекс, EpamAdded:
Yes, hello everyone. My name is Marouf. And I am a course worker at the UOM company.
I've been writing bkand for many years now, well, for the last few years I've been actively writing in Go, uh, before that I wrote in Payton.
Here. And today I will conduct a mock Vladislav.
Well, Vladislav, could you tell us a little bit about yourself in just a few words and then we'll get started. Yes.
Hi all. My name is Vlad. Uh, a few years ago I got into IT as a government developer. Before that, I worked at Rosatom, in the supply department and in the economic department. That's why it is like this. Well, that's basically all there is. Ah, okay. Cool. Oh, look, I sent you the link. Ah, can you please open it and rummage around your screen.
Okay, yes.
Well, I don't see anything yet.
Mm, it seems to be displayed.
Yeah, I think I looked around. Okay, okay. Yes. So. Ah, okay. Ah, okay. So, I don’t know, it doesn’t show up for me, but Well, okay, if others see it, uh, that’s enough, because I generally have a link, I can watch it. Look, today we're going to have an interview in this format, where there's some code, and, yes, and there's some business task. A person wrote code, you need to review that code.
Now I'll tell you a little bit about what this code is in general. And we have, well, let's imagine that we have some kind of system through which some orders are made there. There people buy some orders and pay money for them. And payment for these orders goes through the vendor API.
Well, let's say it's some STPe or some other payment system. A, that is, our hypothetical store redirects the vendor page to this vendor.
A person enters their card details or whatever they're paying for, and then clicks "pay," and after that, the vendor's IP comes to our webcam and says, "This payment has this status." Well, I don’t know whether it passed or not, maybe there was n’t enough money or something else. But sometimes there are failures, like a message, a request didn't reach the hook, or something else. Well, they're also writing in the chat that I'm the only one who sees email instead of code. And I, I, I, by the way, already see the code. Here. And our task is to write some, some worker, which takes, uh, periodically, uh, goes and checks the status of these payments. Here. Ah, well, accordingly, in front of you is the code that the developer wrote, the syntactic code is correct, but it contains a certain number of bugs. You need to find these bugs, and then comment on them, and then we'll start fixing them.
Here. So, what does this code do? Well, this code takes some, uh, some portion of payments that need to be checked, yes, it checks their status, updates it, if the status is, like, about, well, like some final status, for example, whether it’s fail or heaven, yes. Here. And then, if the status is successful, that is, the payment has gone through, we send a certain event to the queue.
Some event in the queue. Through this event, we further distribute this information about the payment having been made throughout the entire system. There, based on this information, the order starts to be processed, there we may send a letter, there we received your payment, there we will now send you your order. That is, we must guarantee the delivery of this message, that if the payment has gone through, then we send an event to the queue about this, about this, about this event. This is a little lower in the logic. And, accordingly, you need to read all this logic. There is about 120 lines of code here, and somehow, somehow, somehow, comment this code. E.
and find tanks in it in it in it. Yes.
Well, let's watch now.
That is, we have a client, that is, this is a method for calling an external function. Yes, yes. Yes. That is, this thing accepts the transaction.
This thing accepts a transaction and returns some status, which is stored on the vendor's side. Yes. Yes.
Payment pay. Oh, okay. OK. Maybe we'll understand the context later.
Message message status verification worker.
Database client queue.
[clears throat] We assemble all this with a constructor.
Враты полочере задаці от Венда.
Eh, I'll clarify one point right away. Do we mean that we will have one of our application spinning or several? There may be several, because, for example, if the number of orders has increased and for some reason the web-buying service is not working, our worker will have to process a large number of these payments and there may be several instances. Yes.
OK.
Process one.
This is V. V, we have this process one m Well, okay, the first thing I see is that we don't have select for update, uh, what is it called.
If we're taking records from here and we're going to process them somewhere else, and we have several Instagram apps running, we need to set up a system that will block the ones we've taken.
Skippt follow, I think, or something like Skip F, I think it's called. Yes.
Uh, skip for log. I don't remember exactly how it's spelled, but, well, it's called skiplock, that's how it's spelled, yes. Uh, then we scan it all, uh, launch the batch.
The only thing I can't understand is V processф, yes, it goes away. Uh, in other words, we have our process fun, uh, where we have uh, a little bit lower a function, there is a little bit lower a method, and, a little bit lower it will be. OK. And here he is.
Well, yes, here is the process. Yes. Yes.
OK. Next, we launch the payment context here, getsta status by context, we select p vendx transaction idshe, we start reading the statuses, if we have the content status, we update the record here, we begin to complete our database, because we begin to make one update at a time. It would be better to rework the logic to add some bachin to update this bachim. Yes.
Uh, so there is a tournament. Then we generate the order id amount status update message.
Uh, so it's like Outbox implements all of this, yes, as I understand it. That is, we have a transaction outbox pattern. So where is the outbox? Well, there is no Outbox yet.
No. We're just getting an update here, it turns out in the payments table.
Yeah.
Then again, an update occurs here.
Well, look a little higher. There, if there is an update happening, if it is A, yes. And there is.
Ah, well then again it’s better to do all this using batching. so as not to write one by one, because, if I understand correctly, we have a forange bach, we form bachs, and for each of these we launch a separate bath process and - well, yes, that is, we make one request and then try to write. Ideally, I would maybe redesign some structure, uh, somewhere in some separate worker pool, that is, use workerpol cartridges. uh, just launch a worker that will make external calls, take it all into a batch and pass it on to the next worker, which will directly make changes to the database. And since we're on the subject, what we're seeing here is pushing into our queue, that is, into some broker. And if our pushing fails, then our records will be lost and we will need some kind of outbox pattern. Yes. Yes, I agree. Outbox putter is a good thing.
Ah, yes, this is something that I saw critically.
So, I have a mouse with autoscroll here.
Uh, yeah, basically, that's all for now. Well, that's just what I saw for the first time. I need to look at the code here again quickly. This turns out to be just vender status, by the way, where do we use status? They shoved it in, took it, scanned it, added it to the patch, and checked it for errors.
So, we checked for errors.
We launched the fun process, again done according to context. This sokh was collected, checked, and recorded.
And for the status, it is used here in the ifest, whether it is equal to fail or not equal there, right? Ah, and the question is, is this Gето transaction status a paid procedure or a free one? That is, we can, roughly speaking, complete the external ventor with this and constantly A, yes, in general, you can call as many times as you like, there is syling or whatever the rail limiting is, this is kind of their problem, we think.
Well, okay then. Ah, well, damn, my God, I don’t like this logic, the way it’s written. If st vender paid if st vend failed.
In essence, there should be a check that we immediately have vend. Well, I would take it somewhere like this, yes, because it reads terribly. Yes.
Uh, just a failed update. Return e. So.
Uh, that means we have a fail, which means there can be three constants. What else do we have left? Uh, fading and penddizing.
It turns out that if we have a pending status, by the way, I’m like, Oh, uh, we need to restart it again. with uh failed, that is, yes, paid.
By the way, we don't process pending anywhere. We need to, uh, ideally, do it in such a way that we can process pending. And, roughly speaking, we started this processing a little later. Yes.
Because we don't have pending anywhere. Yes. Yes.
Accordingly, uh, if we, roughly speaking, work out the changes and do some kind of off-boxing.
Basically, that's it, I don't see anything anymore.
Okay, good. In general, no, in general, in general I agree. And here's a little higher. Yes.
Higher, higher. There, where aa is, where we select the patch. There is nothing that bothers you in this request.
Select order ID.
Well, besides what you already said there for updating skis.
А м бонь vender. By the way, what is the vender status?
No, this is some kind of conditional internal status of ours. Uh, well, I can give you a table of how it was created. I'll show parts of the conditional request there, I don't know how to write comments here a little lower.
I'll see, and then, well, actually, order by right away. What else is just that? What I see right away is to filter by some value, like order by created desk order.
Here is some kind of table. There at the very bottom I wrote, and there is a table diagram. Yes.
ID order ID0 not status Pfil.
Well, these are like three statuses that correspond to the three statuses of what the venter can return, yes.
Mm, well, since it comes down to it, essentially, the process is given to us.
Overall, look, you can expand the table if you want. You can extend the structure, you can change this code as you please, yes. But I have a general question about this select. Doesn't anything bother you about this selection?
But we don’t actually need anything from this selection. We further process only -э Pvender TX idм is needed if you look further in the code. And then select update. Again, the status is update, so we transfer the status here to VIDs.
Yes, in fact, we don’t need to pull out all this. Essentially, we only need the ID. That is, the order ID is external, yes, the ser call ID will be external.
Mm. But Or ID is the order ID. ID is simply the payment ID within our system.
Vender TX ID is the ID ID ID ID ID of this payment in the vender system. That is, yes, that is, the vendor also has his own ADS number, which he used to register our payment.
Yeah, well we don't need the other fields, we only get a vender. X1 does not need to be removed.
OK. And here's another question. Is it generally necessary to somehow limit the number of recordings that we select or not?
Ah, yes, it should be done in a good way. So, it turns out that we will extract all the records and, accordingly, well, [clears throat] there will be a big, huge request, and, accordingly, our other replicas will not receive any records. That is, in a good way, skip for fog and, uh, set some kind of limit and set some kind of set.
Well, why the offset limit?
Yes, yes, by the way, here it turns out that our status will change and therefore our conditions will always change.
That is, well, in this way.
Firstly, it turns out that we only leave the vender XID.
Mm, so, we still have the status there checked every week just in case we pull out something wrong, right? In principle, he shouldn't fly out.
And you, don't you need an ID so you can update your entry later?
Oh yeah, you'll still need an ID later.
Uh, yes, in principle, we could make an update using the vendor ID, yes, for example. Yes, it is possible, yes, in theory it would be possible to do so. Uh, so, ah, here, by the way, the question is, how will the indexes be built, if we have an index here and there, like, ah, ah, such a question, what kind of, I don’t know, what kind of indexes would you build?
Well, specifically in this query, I would probably, considering that we will have a select, and then one update, we could just put a regular B3 index here, right? Well, that is, on the X ID, uh, that's one, right? And the second one, due to the fact that we will be constantly tugging at statuses, it would be good for us to have the status filtered.
Uh, well, in theory, we could also install BitTri, but if you think about it, uh, in fact, we will only have three fields there, and this can be divided, I need to reread.
theory. Maybe there is some more suitable index for this, so as not to use B3?
No, you can bit index there by some field, and also add conditions there.
Well, there's an index, an index, an index there, when you create an index, there you can, firstly, indicate on which fields, yes, there. Uh-huh.
What fields are used to build the index? It is also possible later, knowing the conditions, to add, yes, so that only certain construction projects are included in the index. Well, for example, where you write status.
And you will have an index only for your lines, where, for example, with some status.
I understand, but to be honest, I have never encountered anything like this. I didn't even know you could do that. Type of selective index.
OK. Yes, we are not talking about indexes now. I would like to, yes, correct the code now at this more applied level.
OK. Then here's the question: you're suggesting select for update, ah, if I understand correctly, and this question is related to select for update. If we use select for update and, for example, our worker crashed there, I don’t know, out of memory or something else, these rows may remain inside the database, and, in a state, uh, locked.
How do you, uh, how do you solve this problem in general?
How do you make sure they don't stay blocked? Yes.
Try to throw in some context, probably, and uh, with a timeout, so that after some time, it would simply be cancelled according to the context.
So what was cancelled?
Well, I mean the request itself. That is, I don’t know how much this logic will work. If not, look, look, look. You chose the lines, you chose the lines. I don’t know, I got a 10-year sentence and blocked them at the database level. Here at the post-gas level you blocked them. And then, when you were processing this batch, you had this worker, this Nance worker, it crashed, and the memory ran out or something else, and you didn’t have time to make an update so that the lock would be released. Yes.
Wow, I need to read about this. Eh, I don't know either. Most likely, there should be some kind of instruction that will keep this data in the bat for a certain time.
Because if our worker crashes and nothing happens, we won't make any call to the database. This means that we need to take this into account in advance in our request.
That's a good question. How so?
How deeply have you worked with Selefa, how well do you understand how a lock is released and how it is not released within a transaction, without a transaction? How well do you understand this? No, I have n't really delved that deeply into the pod itself, that is, I know that such constructions exist, yes, uh, when I read about them, but I've never actually used them directly in my work, so I won't answer that question.
That is, okay. OK. Fine. And then there’s another question: look, a little lower, there, where One is.
M A is where One is. Look, here you offer Outbox there when sending a message there. Well, yes. Here it is. Yes, yes, yes, a little lower. Aupox. What is outbox anyway? Can you tell us a little about him?
Fine. Well, basically, what is this pattern? Stras outbox is a pattern that makes, let's say, two recordings at the same time. One entry in the table, uh, Outbox, that's what we'll call it, yes, and the second entry, it updates our data, our main tables. This is done within a single transaction so that if, how can we say, uh, one of the records, uh, for some application, the liver is canceled, uh, so that we can do a rollback and roll back, accordingly, the data for one of the tables back. And, accordingly, in the next one we create, it turns out, a worker, which will walk, check our Outbox table and, accordingly, send our values to the queue. And, accordingly, if it sent the value to the queue, then it makes update successful, let's say that the message was sent. If for some reason it didn’t work out, then [snorts] accordingly, we don’t make an update and just try to send the next one. That is, this is an increase in the delivery guarantee.
And okay. I understand. So here's the question: look, so we end up working with two tables, right? That is, first we work with the table there, update, well, we do something there, payments. And then we have some other table there for transactional outbox.
Here, some kind of transaction is needed in order to have some kind of consistency, so that if, for example, one request works, the second one does not.
Yes, a transaction will be needed for such a question. Yes, if it’s a transaction, can you tell me the boundaries of this transaction so that I can understand where our transaction begins and ends.
Uh, it starts here.
Ah, well, even a little higher, if we have it higher up there, uh Ah, by the way, we don’t really need anything here, yeah, nothing. That is, it will start here.
Uh, then somewhere around here we'll have another update, an Outbox update. Yes.
And then here transaction closeт коит.
Oh, koit. Yes, Comit. Yes. I have n't written them for a long time, of course. OK. That is, in theory it should be like this. Naturally, somewhere here we should have some kind of rollback standing through the defender. Yes. Right away. Ah, good. OK. Well, this is clear. Ah, well, that's good, that's clear. Then I am also interested in this question. Let's scroll up there, where we actually select this patch. Yes.
Such a question. Look. Mm, ah, look, look. But still, look, for example, we selected a certain number of records, blocked them, started processing them, and the worker crashed.
But what if, say, a worker crashed, and, let's say, those records remained blocked, how would you solve this problem? So imagine that okay, you don't know how it works there, how the lock is released there, if you don't have a transaction here, there's no transaction in this place and you did something like this, like conditionally select for updates, how would you suggest writing it here. And, for example, if there, uh, starting from line sixty-eight, yes, somewhere there a request was made, we scanned all the lines there and began to process them, and this Worker instance crashed.
all these lines remained blocked and will no longer be processed.
So, how would you solve this problem at the level of your code? Could you please reflect on this topic?
Well, the question here is that some constructions need to be used when working with SQel. M, maybe I do n’t know now, but I can just ask abstractly, can I do this, can I do that, and in order to ask you.
Yes, you can, you can, you can. Uh, okay. Is there any way I can, say, check how long they have been blocked?
Uh, some probably not. That is to say, no.
No. OK. Uh, then look, how do you look, how can you even understand that some of your rows are locked and that the POS won't even give these records to other transactions, other workers, for reading? Yes. Well, because you took Select for update, yes, there, uh, maybe then you can try to change the blocking level, not Select for update, set some other one.
Uh, what's the question then?
Look, look, here's a hint for you. You can introduce some additional status, and, at the level of your conditional application, yes, there, say, log, and select these lines select for updatem, set them to some log status and perform these two operations within one transaction. Yes. Well, that is, you do selectр update. Yes. There are 10 records there and inside, uh, inside the transaction, you do select for update. Next, you update these lines. You set some log status and then commit. And that's all. These lines, as if on a logical level, were conditionally blocked. And when you've processed all these lines, you assign them the required status, like the status of this payment, failed or something else, yes.
Here. Oh, and you can also, for example, ensure that, since your status has changed to intermediate, yes, the elbow, other workers won't take it from you.
Here. [clears throat] Uh-huh.
Well, there is another downside here. I said it this way on purpose.
Can you think of any downsides to this kind of trick?
Mm, well, what we get is that we'll have two simultaneous visits to the database.
The only thing I have is, yes, for example, to what extent will this work, specifically, that select for update. If we take it, create a transaction, then do a select for update. Well, then we'll update our lines with the second entry. Yes.
And that is, uh, at the moment of updating these lines, I don’t know, the database will conditionally be unavailable there for some time, yes, or our worker will crash, then we will have a defer transaction lback, it will not work logically.
Not for you, like, okay, not for me, I did n’t quite understand, but [clears throat] stay in the status, well, your lines will remain in the status. Yes.
How to process them, how to process them? That's a good question. So, how would you finish them? There's another trick here.
How can I make it so that these lines, which, for example, are stuck at the logical level of blogging, through this status lock, how can I make it so that they are processed? Well, for example, did you take on another worker, for example? Well, that's exactly it, that's a good question. I don't know, honestly, I need to think about it. You can try using a higher blocking level, because, as far as I remember, there are different blocking levels in Povis, and there are some that block each other, and there are some that, roughly speaking, exclude each other. Maybe try with a different level, try to extract all the records in the processing status, yes, but only with a different blocking level, which this script foundate will bypass, that is, it will surpass.
Well, I don’t know anything like that, to be honest. Yes, but here it’s okay, yes, I don’t know, it’s okay. I'll just give you a hint on how it's usually done there, except for the additional status, which is introduced, we have three statuses, yes, now let's say four, there's some kind of lock, yes, and also some field lad is introduced when we logically blocked it, yes, and when selecting, we look not only at the pending vendor, but also at the conditions of either pending vendor, if no one has taken it before, or status locked and it was taken and then blocked, for example, there 2 hours ago, there, it hasn't been processed for 2 hours, which means that the worker who took it, it crashed or something happened to it. And this record, as it were, got stuck in the a-e in the status of elbow there, so to speak, yes. And these 2 hours, it could be, conditionally, half an hour, an hour, it doesn’t matter, and everything will just change as if the request changes.
Okay, let's go. And then, as if during the retreats, another worker could take it conditionally. This is the question, OKLY, OKLY, generally sequentially process these records, you see, a little lower, a little lower there is process one.
You suggested rewriting them somehow, you can try rewriting them somehow so that it would be, well, each of these transactions is a conditionally independent object. Yes. In principle, we could somehow, I don’t know, parallelize them, yes, it’s not necessary for each of them to wait for the other.
Ah, yes, in principle I agree here.
The only thing that will happen then is that somewhere in the functions above, uh, each function is launched separately. That is, simply throw these batches through the channel and, accordingly, so that each Gurtina works on its own batch of data. That is, do n’t wait, you already have a batch of ten records there.
Yes, yes, yes, yes.
Here we are, I am talking about distributing exactly these 10, namely these 10, in order to paralyze, yes, these, well, for example, as an option, yes.
Okay, then, well, again, we won’t move away from the channels. We'll just create some kind of pullworker opponent somewhere above. Come on, let's try to write some code that will somehow light up the processing of each payment, so that they don't have to wait for structures.
Well, by the way, I might add that there's certainly more than one option from the half-workers; you could also try writing a serialization. Well, there are two options.
Any option that seems good to you.
Well, workerpol is always, well, in most cases, of course, it seems to me to be a better option.
Uh, uh, so. So, the workshop, let's say, has been declared, uh, a vat.
That is, we pass a structure of the payment type there, that is, payment.
M. So, if I remember correctly, this is how it’s done. Then we will worry about the buffer size, which one is better to set.
Well, that's a question for you. I don't know, are you going to bother?
Uh, well, in general, at a minimum, the number of buffers needs to be greater than the number of Well, I mean, the buffer should be greater than the number of workers, properly speaking, that we will launch.
The question is for how long? Well, let's make it 10 for now, okay? Let's just declare some constant 10. If anything, we'll come back to this issue.
Const is equal to 10.
So.
It turns out that the syntax is a little wrong with the ad, but in my opinion this is how it's done.
We declare a sphere of size 10. And so we did it, but we did n’t start the workers.
So, uh, let's do it this way then.
Now we will announce our type of worker. Let's return this worker via the link.
M so. We have a fingerprint here.
Here.
And so, next, to be honest, we need to start workrk.
OK. Let's imagine that we will have, well, then let the number of channels of the buffer be equal to the number of channels, like.
And so we still need to change the signature.
That is, in our process one, payment is passed, the context is passed, and an error is returned.
[snorts] What's going on there if we returned it? And we just have logging going on. Okay, then we don't need this, in a good way then.
So, process one. We do it. Here we must then start the workers and two exactly equal to zero [snorts] and less than size and plus-plus.
Uh, we'll launch it next.
So, we haven't added the synchronization group yet. We will need all of this here so that later we can do it.
Now, look, I don’t really understand what this forcycle is doing inside the constructor. Usually, look, usually we don’t write such logic inside the constructor. That is, well, like a designer, he creates something and that’s it, that’s all. That is, he initialized something there, that’s all. Yes. And I'm not really into this kind of stylish description of code, when you write something inside the constructor, launch some pictures or something else.
Yes, I understand. Uh, well, basically, yes, I agree here that usually there is some kind of star function that does all this.
Well, your start function is just run p ones, that is, this is one. Yeah. [clears throat] processing cycle of these. Isn't this contribution point enough for you?
No, why not? Can. Let's just say how to write it. I just didn't want to create an extra feature right now and waste time on it. OK.
If, well, I mean, like, look, you already have an entry point, I mean, runes, right? That is, this is precisely the entry point of our dada. Yes. Rpol processes a portion of payments, and then there's some kind of conditional, for example, it runs inside some Kubernetes codes, there you have some kind of supervisor who runs this workflow for you, yes, and increases the quantity there. So, in short, the entry point is runp ones. [snorts] Mm, if this is the entry point, run, but we have it somewhere at the initialization stage. It's just that if I initially wanted to do it - like, uh, like this workerpol, yes, then if we have a run entry point, then it's probably better to use maformere because I can figure out how to do it faster. Uh, okay. Then if we do this in 2 seconds, we will take Go Fun. Uh, so, coffee. Let's move it here.
And then we must now occupy the signal immediately.
Okay, wait a second. At what point is it probably best to occupy the traffic signal? at the stage, probably, when we will record the patch, just a second, now is right. I'll just try to quickly make a pathofo to run it there.
Give me the tract here.
Make a chanct here.
Well then, with a semaphore, we need to take into account that each process will be processed separately.
Okay, then we have a structure there.
Uh, just a second, we just need to think better now about where we will take the semaphore.
If we borrow in a cycle, we will lose, in principle, it’s normal. If we are not in a cycle, then our grouting will simply stop at the van process. No, not a very good situation, I guess. Then we take our uh V point uh channel CX we will place uh empty structure.
Once we have this worked out, we will read the structure from V dot CH.
And how did you understand on line ninety-seven that your goroutine would work?
Ah, well, here it is, inside our gofan, inside our routine. That is, if we have an if processed, we have a post, it will have to come here in any case.
Ah, yes, yes. Yes, okay. Everything is fine. It's inside the Fanta, just a little bit of this, yes, like this, so that it would probably be easier to read. Something needs to be done. Uh, so. in a good way.
Well, if you have some kind of function, yes, probably, it has, well, first of all, it needs to be called, when you run the routine, yes, there should be a function called, yes, there should be parentheses on the ninety-ninth line, on one, it ca n’t be on the ninety-ninth. Yes.
Yes, that's not the case here.
When you run it, you actually call some function. Yes. Yes.
Uh, accordingly, well, a little bit of syntax, I don’t remember. That is, in my opinion, how it is. Oh, wow.
No, no, no, no, no, no, not like that, not quite. You have go, keyword, function call.
Ah, I get it, I get it, I get it, I get it, I get it. Yes.
Eh, the brackets weren't the right ones.
No, wait. as if the body of the function was inside the correct brackets. But here you also forgot, empty parentheses are like variables, right?
Here you go. And yes, and accordingly the fan is empty remains, then the type of error return is also a body function.
Function body, yes. And here there should be this extra bracket on the left. And also, as if calling this function, also round brackets.
for money, right? Yes. It's like you called a function. Yes.
OK.
We haven't created a group yet. That is, there will be no need for a group here. This is the good way.
Ah, well, for us it will just start, everything will work out. But basically, uh, no, we don’t need a group here yet. The group will just need to be closed. That is, if we have this working at once, it distributes 10 workers, that is, we launched 10 gurutins, 10 gurutins returned to us with a response. And, accordingly, after this we must close the channel, that is, to lose the memory. That is, accordingly, it means that our channel is already leaving initialization.
Uh, we're removing it from here everywhere.
We'll announce it somewhere here. Let's say, equal to - the CH will be here, will be here.
Then we have to announce the wait group. But if we don’t announce a wait group, our logic will work and nothing will happen. Eh eh sin, yes, I think so. The package syn contains group. I apologize a little for the syntax. I'm used to writing vdshki.
Nothing is highlighted here, unfortunately.
Uh, so, by the way, in our new version of Goshka you can actually make VG GO like this. Yes.
And launch all this beautifully. Then we will have this uh -uh and so our cycle is recorded. VG weight. Yes.
VG weight.
There is a mistake. OK. And accordingly, then H is superfluous there after yes. Uh then close our channel.
I think that's how it's written. OK. OK. It's been a while since I wrote code like this. Okay, make a channel and that's basically it.
That is, we will launch Prosfan. Uh, and so we drew this patrim in a cat. Yes. Ah, okay. OK. Only there, on the eighty-ninth line, one group is missing. Brackets at the end. OK. And so the pattern pattern simuhor was implemented.
Fine. Yes.
Aaa so good. Such and such a question then mm what if, for example, Uh- huh.
and some records are not processed at all, right? Don't know. We have some kind of broken line there. When we try to process each, uh, each record, we get that, uh, this line cannot be processed in any way. That is, we have some, I don’t know, some bad lines. What can you do with them? [snorts] Well, ideally, they should be transferred to tech support right away. That is, we need to implement some logic, uh, that if, well, here again from the logic of the trip, how will we do it, if we are sure that there is some broken string that we cannot repeat in any way, like we can try to read it from the database again, but if the database again stores the same broken value, then this record then needs to be sent, well, either saved to another database, where our tech support will sit and read, like, or forward this message through a broker to the support service, where the support will come and figure out what happened with this record. Yes. Yes. Yes.
Something like this in this context.
That is, if we cannot fix this with code, we will not be able to do anything. If we can somehow fix this with code, of course, then the situation is different. But I, at least, can’t imagine how a broken line can be fixed with code.
Ah, well, well, yes, yes, I agree. Agree.
OK. Fine. So.
Taktaktaktak.
Eh, let's think about this a little bit more. So, overall, okay, we somehow wrote it correctly, let's say, we wrote our worker. How would you even test it, yeah, how would you even test such a thing?
Well, in general, again, write some table tests, right?
What is the best test to write, what to test, what to check? How, how to check this?
Ah, [sighs] okay. To be honest, I have never done this, but I have read all about it. That is, essentially, we need to run some kind of profiling, firstly, through PP prof, to see how many locations we have there, so that we have No, look, I'm not talking about how well it works, but rather just checking that it works correctly, so that it does exactly what it needs to.
Write some kind of table test, mock the call to this function, what it returns there, let's say, always to true, yes, and in the table test count how many grootins we had running and, accordingly, what response we received from them and check, probably, that the channel was closed. Although no, it will close in any case, but such a check was not carried out. So, the code will hang.
Well, that's it, that is, writing a couple of table tests, mocking the coverage, external calls specifically. Do you want to block process one?
Yes, just soak the process one.
Why wet it? Well, I mean, that's exactly what we want to essentially test, right? Let me think a little about what kind of things make sense to mock when you're testing logic like this, for example? What does it make sense to wet here?
Well, by external call, I mean calls between services. That is, if we cover some US CAS business logic with unit tests, then it makes sense to mock the calls to some drivers or repositories that we call externally in cases. This is the meaning of washing.
Well, that's basically it. That is, I was hasty when I said that we need to mock the internal function, in fact, we are checking it, like, yes. Yes. Ah, okay.
OK. Fine.
Well, I guess that's all for me overall.
Ah, I guess I can there, I don’t know, if you have questions, I can answer them.
Uh, yeah [snorts] no, I'm basically just more interested in whether it's even possible to somehow remove the block that we talked about at the beginning. If we skip for update, we will occupy the lock and then we will not be able to cancel it there. But what I mean is that our transaction rollback won't work, some service will simply go out of memory.
And look, look, look, look. It works a little differently. Look, your blocking will no longer be at the Postgres level, but at the level of your application, like the application logic. What does blocking mean? What does it mean that a line is locked? This means that she has a locked status.
Here. And you have this blocking happening inside the transaction. You start a transaction, select some rows and mark them locked and commit the transaction. And if the transaction was successful, the row was locked. If your transaction doesn't go through, it rolls back, it will go back to the status of pending. Yes.
I understand, yes, this, but here's the thing: between the time we selected the recording and before we made the update, we have no guarantee that some other service won't select the same recordings again.
Ah, look, if you started a start transaction, did a select update and that's it, inside this transaction you hold a kind of lock. No other transaction will select these rows.
And this is another level. Okay, I got it. Yes.
You are a little bit confusing row-level locking and isolation level locking. These are slightly different things. And when you took the selector with an update, as if there were some constructions inside the transaction, that’s it, no other transaction will be able to update it, wo n’t be able to do anything with it, as if all this is like an on-lock, this line is locked for you. And then what do you do? Well, you set the status to lockkt.
you make a commit. If your commit passed, it means you blocked it at the application logic level. Everything, like these lines, they are the lines of your worker. Another worker won't take them. But if you somehow fail to comment on the transaction, the status will roll back to the pending pendnen status. Everything is as if nothing terrible will happen and another worker will come.
So there are no problems here.
Well, well yes, in terms of code logic, this is an interesting solution. I actually got confused about the blocking levels at the beginning, but if I wasn't confused, I need to read.
Well, yes, in essence, this whole workkey is essentially an implementation of that very transactional outbox that we talked about. Well, well, a little bit, yes, it’s very, very similar, rather in words, yes, when you put something in your outbox, then there’s a worker that processes it all. Well, imagine that you need a worker, for example, who sends these letters or sends them to a queue. This is precisely the logic of Relay Worker, it is very similar to how this vendor poll is set up here. So, uh, in general, if you know how to implement the Patter transactional box, do something like select for updates with some statuses, blocking at the application logic level, it's not very difficult to read about how to implement it correctly, conditionally correctly, what implementations there are for Transaction Box. Well, because Transaction Box also has different implementations, and they can be implemented in different ways.
Okay, okay. Well, Kavka, there won't be Kavka today. Now I opened the chat. There will be no Caucasus. But we talked a little there about sending messages, but there will be no cavities today. Well, okay, good. Overall, overall I have no more questions.
I guess I'll pass it back then.
Then I appear. While Maruv is preparing, in fact, his unpublished feedback.
Guys, first of all, you go and buy the IOC, and secondly, actually, I want to talk again, yes, as I promised for those who just joined us, about shortcut. We are the number one mentoring program for government developers. We help you achieve your career goals faster, boost your hard skills, and help you pass interviews from an HR perspective. And thanks to all this, yes, we can get you to the offer faster, do it for you faster, and so on and so forth. by the number of classes held, by the number of IOCs held. And we are the number one platform for government developers.
And, actually, in numbers, yes, if we talk about it, we already have more than 20,000 developers in our community. This includes our current YouTube channel, and, accordingly, Telegram bots, and other YouTube channels, and so on, and so on, and so on. More than 2,000 people are already with us. We either passed the IOC interview or became our mentees. More than 500 of them have already received offers. And the average rating for classes in your category is 4.9 out of 10.
Our goal is to make sure your training is as awesome as possible, not just so you enjoy it, but so it produces results. On average, yes, it takes 2,000 to 4 months for our guys to upgrade to a new grade. Yes, on average, if we talk about the market average, it happens somewhere in six months to a year. And, accordingly, at the same time, we didn’t press the button, yes, and we always expect from you that you will devote at least 10 hours a week, accordingly, to training, so that together with you we can, uh, so that together with you we can build a fast track coffer.
So, if you're willing to dedicate 10 hours, we'll evaluate your current skills, tell you what needs to be improved, and then we'll quickly improve them with you, set up an echo mode, and so on. And all this will give us the opportunity to guarantee you five job interviews. We are the only mentoring platform that therefore guarantees you will have at least five interviews. We, at the same time, yes, uh, why can we guarantee this? Due to the fact that we have a very large group of mentors, we have referrals to all Russian IT companies, and, accordingly, there are HRs who will refer you. Yes, and he won't get the money until you have five social security checks.
Actually, everything starts with Mockinterview. Today's stream is an example of the kind of mock interview you can take with us as part of the shortcut.
During the mock interview, you and your mentor will go through all the basics of Goshka in an hour. And the mentor will answer all your questions and, well, then we'll give you feedback and development plans, we'll tell you what you've done well, what you still need to improve, and so on and so forth. And if you don't like it, we'll give you your money back.
Based on the results of the Mock, we create a development plan for you, and you and your mentor follow it. Before each lesson, the mentor will send you the theory; you watch it, read it, study it, and ask questions if necessary. And during the lesson itself, the mentor answers these questions. Then, if you wish, you can go to another mentor to have an interview with them and understand what exactly you know and what exactly you still need to improve. Well, actually, between classes the mentor is always there, available in the chat, and can ask any questions. You can honor a chat mentor, conduct code, homework, or subprojects, or share homework materials.
We already have over 150 mentors, including Maruf, who conducted today's interview, Ramil, Dima Drofeev, and many, many others. This includes Sinir, Midle, midlep, team leaders, and so on. All of this is so you have cool offers. Here are three such charismatic stories that I tell from stream to stream, but in total, as I said, there are more than 500 of them. The first mentor, in a month and a half, upgraded with us.
Yes, we quickly realized exactly what he was lacking, and after that, he was able to, accordingly, improve these weak points and quickly move on to a new offer. On the left here is Menti, she was affected by the reduction, so together with her [snorts] we did about 10 mocks. Uh, she's quick because she hasn't been to the market for a long time and has forgotten what it's like to go through mock trials.
We held 10 MOCs with her, and she was able to find an offer and, accordingly, a mentor who was able to get a job at Biktech Tem Dom. And we have many tariffs. After the mock interview, we'll select the most suitable options for you, but most often, people choose the extended plan because it includes the five-interview guarantee. 63% of cops bought it in April. Well, guys, actually, it all starts with our smoke interview for 2,000 rubles.
It is available here via QR code. You can, accordingly, go to our bot, you just need to press a couple of buttons. And after that, we will, accordingly, send you messages with information about the next steps within a couple of minutes. You pay, the next day we come back to you with a mentor, you will give him a thumbs up.
After this, we create a chat together with the mentor, and you, accordingly, conduct the IOC interview.
We'll call each other the day after the IOC. On average, it takes 3-4 days from the application to the IOC. And 3 dashes, well, 34 just in case, but if you suddenly want to have a mock in 34 days, it will be in 34 days. And then, after the IOC, you will receive individual feedback on what is good, what is bad, and what needs to be improved.
If you don't like the mock interview, if the feedback is incomplete, or if you just want to extort 2,000 rubles from us. You can write to us: "Return the money for the interview lock within a week after it takes place, and we will return everything to you." And I am returning Maruf and Vlad. I'll hold it a little longer. Guys, scan the QR code or use the link in the description to translate. Maruf, can I ask you to give Vlad some feedback?
So, and, probably, according to the FIDK it will be like in two, or in two parts, there as a whole, like reading the code and writing it. And Vlad did a pretty good job of understanding the errors and problems in this code, right? There are some bugs there. Here. And overall, I mostly liked the solutions he proposed. In this part there is a conditional plus rating. Well, but, uh, there were certain gaps when we moved on to writing the code. What I missed was that he would actually fix most of these problems at the code level. They'll write the code directly, they'll write there, they'll correct the queries, so to speak, they'll tell you more about some update, about blocking, and so on. But at this level I gave there a conditional rating of Junior plus and there the conditional average rating is probably somewhere around midle minus midle, yes, that’s probably how it is. And I would advise Vlad to practice writing some kind of code there a little more, I do n’t know, to solve a little more problems specifically on concurrency, on working with databases at the state code level, and what kind of problems there are. Here.
Overall, the feedback is super, but overall, Vla Vlad is cool. Now I agree. Super. Vlad. How did you like today's sobis? In general, what do you think? What do you think?
Well, it's actually really cool because I like this kind of thing, because it helps to highlight a problem in knowledge. And that is, the more difficult the task, the darker it is. Uh, I'll be honest, I was really worried about select and updates, and like, what Maru then suggested at the logical level is to edit the code. Uh, I still couldn't get rid of this selective update, let's say, yeah, like, here's another funny thing, the thing that got stuck. And it's quite an interesting experience. And, damn, I liked it, honestly, like I’m going to reread the book on Postbs and read more there than doing this. This is it.
Uh, the only other thing I'll probably say as a comment is about the fact that when you made the presentation that we're not a money button, yes, in that format. Uh, when I, as I already said, before that I didn’t work at Goshka, yes, and, accordingly, I also studied in many places there, bought several courses, but the point is that, uh, the people I talked to, and, as a rule, people who didn’t study there for 15-20 hours a day, who don’t know [ __ ], let’s say, yes, they were never able to switch. Those who were just cramming hard for a year, they didn’t switch. Therefore, everything is in your hands.
If someone wants to do something, then do it simply. Yes, I think it's also about how much you really need it, yes, if you're super ready to really get into it, ready to spend a lot of hours on it, I think it will work out, of course, yes. But if you do this only to a limited extent, because it’s some kind of obligation, everyone goes and I go, well then it’s more unlikely that it will happen. That's why I think this is the level of motivation. If you have a high one, you will succeed. My opinion is this. But please don't quit your job.
By the way, I didn't quit. I stayed at my old job until I received an offer. And then he said: “Well, I’ll come to you in a month.” It just happens often that they correlate, that the cops come in and are motivated like, "That's it, I've already quit all my jobs, I'm ready to sit 15 hours a day and do all this. Just give me the whole offer, let's go." But it's kind of difficult to work with.
Well, by the way, 15 hours, sorry to interrupt, 15 hours a day is not much when you don’t have work. 15 hours a day when you work at work and also study is already a lot.
OK.
Uh, Marouf, who did you like from those who answered today? Are you muted?
Oh, sorry, damn. Yes, I generally liked the comments from two people now. Eh, now this is the right way to pronounce nickname. Maurice Frank 1984 and MXMRN or something like that. So, guys, we're giving you a free Zoom referral. If you need it, write to me, I will send you my cart, drop me a line there.
I actually have a lot of personal messages there right now. I might not answer you today, maybe I’ll answer you tomorrow, but at the very least it will be on the weekend or Monday. But everything will definitely happen. Accordingly, as I, or rather, as we promised at the beginning of the broadcast, I am in a bit of a hurry today, so we will not have e-answers to questions. Thank you just for coming to see us today. Thank you, Marouf. Thank you, Vladislav. Ah, Vladislav, it was also very nice, in general, to talk to you and it was very nice to see you.
I think you have a pretty inspiring story. Thank you for sharing it today. Here. And, actually, the biggest thank you, as always, to you, our dear viewers.
Thank you for being with us today.
Without you, we would be strange people who don't understand why they even do these streams, but you fill them with meaning.
Thank you for watching us.
Come to us, of course, for a mock interview. Have a nice evening everyone and bye.
Yes, thank you all. Bye.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
🚀 BCS613C Compiler Design | Module 1 to 5 Schema Evaluation 🔥 | VTU 6th Sem 💯 #VTU #bcs613c #exam
Pranavaa-y4y
104 views•2026-06-02











