In this chapter, we're going to go over some final bug fixes and improvements in our application. This will include learning how to increase the sandbox expiration, making A2B template private so no one else other than your team can use it, improving our conversation history from the previous chapter, and overall error handling improvement in our application. So let's start by learning how to make our sandboxes last longer. As always, ensure that you're on your main branch and make sure you have synchronized your changes. The last chapter we merged was 18-Agent Memory.
So let's learn how to increase sandbox expiration. Right now, instead of our application, if I visit even this one four minutes ago, okay, this one works. But if you visit anything older than five minutes ago, it will show this. The sandbox wasn't found, which is not ideal if you're doing some presentation or if you're showcasing this to someone. So here's how you can increase your timeout.
So the sandbox life cycle, it will stay alive for five minutes by default, but you can change that using the timeout parameter. Now of course depending if you are on free tier or if you're on premium tier you have different limits. On premium tier you can keep it alive up for 24 hours but on free tier which we are on we can keep it alive for one hour. So for example let's find something in between let's use half an hour I think that's a fair amount. So all you can do is go inside of your functions, instead of the ingest folder, and in here when you create it, go ahead and do await sandbox.setTimeout and now you have to enter in milliseconds, right?
And in here you can see so the maximum time a sandbox can be kept alive is 24 hours for pro users and one hour for hobby users. So if you want to you can set this and then this will be alive for an hour. But keep in mind, the longer you put this, the more credits are you going to spend. So what I recommend is, you know, find a middle ground. This is half an hour, so you can put this instead.
And you also have this util here I believe. GetSandbox. Now in here it's also important to increase it but you don't have to put half an hour here but yeah let's be consistent and let's put half an hour here as well. I just want to be careful and I don't want you to spend all your credits but perhaps maybe add this to some kind of constant here. Types.ts export const sandboxTimeout and add a comment 30 minutes in milliseconds like this and then you can consistently use it in different places And you can easily change it if you change your mind.
Let's go ahead and add that here. Sandbox timeout. There we go. So now we know how to increase our sandbox timeout. And I will try this out.
I will do build a calculator app here. And, you know, at the end of this chapter, I'll, I'll see if it still exists, if it manages to do it without errors. So let's see, what else do we have to do here? We just learned how to increase our sandbox expiration. I'm going to leave this for last simply because we are in the middle of generating.
So let's go here. Improving conversation history. So in the previous chapter we learned that we can add previous messages and we can add it to the state. And I've been experimenting a bit, and I think I found kind of a perfect combination. So what I think we have to do is we have to limit our messages history, because the longer the history, the more confused the model gets.
At least that was my experience. So I limited it to five messages. I'm pretty sure it would work great with 10 messages also, but five was somehow the sweet spot where I was able to keep a conversation going and do some small changes constantly. And then the proper one is actually created at descending, but make sure that you do reverse in here. So it's actually ascending.
You need ascending here, but since we are limiting the take, we need to offset, right? You can also do the offset thing. Actually, it is skipped in Prisma, but Honestly, I'm not really sure if we need to do that, but we can just do it descending and then just reverse them here. And this, in my opinion, gave me much, much better results than anything else. So again, I invite you to experiment.
But once I did this, so I keep this at descending, I limit this take to five, and I reverse the formatted messages. And this made the AI understand much better what I'm building. So for example, let me do make it glassy design. I'm going to try and do this. So we're going to see.
Okay, so we did that we improve the conversation history. And now let's talk about error handling. So error handling in our app currently doesn't exist outside of tRPC procedures, which means that all of our suspense can go wrong. So here's what we can do. We can do npm install react-error-boundary.
And let me show you my version here. So package.json react-error-boundary 6.0.0. And then let's go ahead and find a random suspense here, for example, for loading the project. So how about we add Error Boundary here and wrap it in Suspense. This is how you do error handling if you want to do it on a segment level.
Next.js also comes with its own error boundaries which are written the same as pages. You would have error.tsx. You can of course add this as well but I want to show you this. So I'm not sure if this is error boundary from react error boundary. Okay, I think it needs to be like this.
There we go. And then in here, you will add a fallback error, like this. So first, let me just check if this is working. There we go. Glassy design, glassy calculator.
You can see it understands the context. Perfect. So let me show you this now. So first, without error boundary. So comment out error boundary.
I'm working inside of project ID. Let's go inside of projects.get1 here. And in the query, I want you to throw new trpc error here with code bad request. And refresh here. And in here you can see it's loading project it's loading project oh yes my apologies no I'm trying to demonstrate this but I forgot we commented out error boundary.
And this happens then. This is obviously not good. We don't want this to happen. That's why we have error boundaries like this. So go ahead and refresh now.
And again, it will keep trying to do this for three seconds, for three attempts. One, two, three. And then finally, it will hit the error. And this is what you can then design as your error page. So what's important is that the error boundary is around suspense.
Now, this doesn't make too much sense because I'm wrapping the whole page here, but imagine if... Of course, let's just remove this TRPC error from here. Imagine the case where I'm doing, where is it, UI components, where I have the project header here, right? So let me see, where do I render project header? In the project view.
So go inside of your project view. And in here we have suspense. So the error boundary from react error boundary would make a lot of sense here. Fallback project header error. Like that.
Or in here, error boundary again around this suspense with the fallback messages container error. So now, let's say we go inside of the messages here. Let's go inside of messages get many, and let me just try and do this. So throw new TRPC error here, code bad request. So something happened here.
And let's go ahead and refresh here. You can see that the project has loaded and you can see it's trying to load messages. It's trying to load the messages until eventually it fails. And since we added the boundary, we only see messages container error. But if you didn't have that here in the project view, if you didn't wrap the error boundary, let's see what would happen then.
So let's refresh again. So it's loading messages, it's loading messages, and you already know what will happen. The entire screen will error. So just like minimizing the loading state, you can use the error boundary to minimize the error state. So that's what you would do, right?
That's why we use the error boundary. So I would recommend, you know, finding all the suspenses that you use in your project. And I think these are the only three, so we just added to all of them, right? And you can also do the following. You can also add inside of source app, you can add a page called error.tsx.
Now this has to be a client component and in here make sure to call it error page. Don't call it error, this is a reserved keyword. Call it error and you can return here global error. You can, of course, design this however you want, but this is useful. So this right now doesn't do much, but let's go ahead and do this.
Let's go inside of project ID, And let's say we forgot to wrap this error boundary here. So now, and yes, also go to Project View and comment out the error boundary here. Now the global error takes care, right? So that's how the global error works. So if I didn't have this, let me just remove it now.
If I didn't have this, this is what would happen. Let's say we forgot all the inner error boundaries, right? This happens. So this is the one thing you don't want to happen. This error just looks ugly.
It looks like something really, really broken, right? That's why you want to make sure that you have the inner Error boundaries. You want to make sure that you have your individual page, error boundaries, and you should also have your app, error.tsx, simply because it is the last line of defense in case something goes wrong. Perfect. So now let's go back and set up our messages procedures here.
Let's just remove the throwing of the error here. There we go. Perfect. Now what I want to do is I just want to go to the usage.dsx here component, and I'm really worried about this format duration for a simple reason. Dates can often cause errors and it would be very stupid if our entire app here fails just because the date is invalid.
So here's what I think we can do. Let's go ahead and try it. So I'm going to open a function like this. And let me just close it here. And I'm going to open curly brackets here.
Let me close that here. And I'm going to open, actually, here's what I'm going to do. Instead of trying to do it here, I'm going to just do const resetTime useMemo like this. Make sure you added useMemo from React. And then inside of here, what we're going to do is we're going to open the try, and we're going to open catch.
And in here, let's add a little error. And let's do console error. And let's do error formatting duration. Error. Like that.
And let's simply return soon. So it will just say, or maybe unknown. Or whatever you think is better user experience, right? And then in here, let's return format duration, and then inside interval to duration and then start new date and let me just copy it and it will be this And then we're just missing the format here. There we go.
And in here, let's add MSBeforeNext. And then we can use this constant here. So, resetsIn, resetTime. Let me just check if it still works. There we go.
Resets in 29 days and 20 hours. Because now if this msBeforeNext happens to be something like not a number, there we go, resetsIn now doesn't work, and it doesn't break the page. That's what I at least wanted it to happen. OK. Perfect.
So now that we have this, actually, I mean, we can try it out by doing throw new error. Whoops. And now it should say resets in unknown. Basically, it cannot block the page, It can still allow the user to work, which is what we wanted. Perfect!
So this is very good. Let's see what else we have on the list here. So we learned about improving the error handling and now let's talk about making our E2B template private. So if you go inside of your e2b dashboard, in here you can see your templates. And you can see that my vibe-nextjs-test2 is currently public.
That is because we have published it. The reason I told you to publish it is because I personally had problems with private templates. But what you can do is the following. Open your terminal, go inside of sandbox templates, go inside of next.js. And since inside of here, we have a E2B tomo file, We can easily just do E2B template unpublish.
You don't have to add any other flags. It will read everything from here, including your team ID. And just confirm that you want to unpublish it. And what this does is the following. If you now go back here and refresh, you will see that my Vibe Next.js test2 is now set to private.
And that means that inside of the functions on the ingest here, whenever someone tries to create a sandbox with that, this will fail unless in their environment their E2B API key belongs to my organization. So what I suggest you do now is definitely try, so let's try make it red. And you can see that this sandbox are still going strong, so it definitely works what we increased the timeout for. So now what I'm interested in, will this still work now that I have made my template private? And I think that it does, since I can fetch the sandbox ID.
For me, it happened that the sandbox ID was not able to be fetched once I changed it to private. So just make sure that it still works here. Let's see, make it red. There we go. And you can see how the conversation history is improved.
It made it glassy and red, exactly what we wanted. So we definitely improved the conversation history here. And for me, it seems to still be working. If for whatever reason yours stopped working, it shouldn't, but you know, it happened to me, so maybe it will happen to you. You can easily go inside of here, inside of next.js, and just run e2b template publish.
You don't need any arguments. You can just press publish and then you can confirm. And then from here you can go back inside of here, go inside of your templates and see the status, make sure it's public. And you can even do that from here, I think, by clicking here if you want to. Perfect, amazing.
So I think That's all we wanted to fix. And there is one thing left to discuss, and that is, let's just search for it to do. Instead of messages container, we're using refetch interval as the live message update. And I was thinking about what I should do instead of this. But initially, I built a project like this, and it worked just fine.
So the thing is, this is not a multiplayer chat. This is a single-person chat who receives responses from AI. And most of the time, you only send one message and then wait for the other message to come back. And we are not just doing any kind of polling. We're doing polling using the 10-stack query.
This means that this refetch interval will dedupe, it will use cache, it will be an extremely optimized interval. And also, I'm not sure if you knew this, but while right now new requests are being made every five seconds, if I change to this page, the requests stop being made. So you don't have to worry that in the background, it's constantly going to fire. It is a very, very optimized polling. And it actually makes no problem to use in our type of application here.
And in fact, you can even reduce it to two seconds if you want to. This will give you a better experience and it will still be very, very optimized. Now, in case you're wondering, okay, but does Ingest offer any real-time updates? They absolutely do. You can go inside of the documentation and read about the real-time.
So in here, you can subscribe to a channel and then from the function, you can initialize, you can publish to that channel. And I explored this option, but the problem was I wasn't able to synchronize both my Prisma messages and the Ingest subscription messages. It is absolutely possible, and it can be a good homework for you if you want to give yourself a challenge and do that. For our use case, polling is more than enough. So I will just remove this from here.
And if you want to, you can move this into a constant so you can change it easily if you're using some polling in multiple places. Great, Amazing. So I believe we are now ready to deploy. I don't think there is anything else we have to do here. So let's go ahead now and let's merge this.
So 19 bug fixes. I'm going to go ahead and open a new branch. 19 bug fixes. I will stage all of my changes, 19 bug fixes. And I'm going to commit and I'm going to publish the branch.
And since these changes were very, very minimal, I think we can just go ahead and merge them because they were just some very small bug fixes here. We can do our own review here. So we added the React error boundary, we added global error page, we added some wrappers here, error boundary, we added the proper sandbox timeout, we properly reversed the messages so the conversation history is improved. We use the same sandbox timeout in the utils here. We reduced the refetch interval.
We made it safely here to fetch the reset interval and we just added some more error boundaries. That's it. Nothing else needed here. We can merge this request immediately. Amazing, amazing job.
That marks the end of this chapter. As always, go back to your main branch here and synchronize the changes and then confirm in the source control that you just merged 19 bug fixes. Amazing, amazing job and see you