Thursday, February 22, 2024

Don't run RHEL on e2-micro

So I wanted to install nano on my e2-micro instance but every time I try to do so it just hangs the entire system.

Turns out dnf uses so much memory that it crashes the system.

I created a 2GB swapfile and then tried dnf install nano again and it seemed like it got stuck again...but this time I waited a few minutes and then nano was installed.

Running dnf install was fast for the first 20 or so items, then it got stuck on google cloud cli for like 20 minutes then I got impatient and just killed it.

Seems like running RHEL-based systems on a GCP e2-micro is just not practical.

EDIT: I used "balanced persistent" storage for this which cost me money. To get free tier you need "standard persistent" which might have worse performance.

Don't close resp.Body on error

So my server finally crashed for the first time today luckily I was running it through systemd which captured the stderr (yay!) so I saw what the problem was. Turns out it panicked in the function where I ping the health check URL. 

So, for context, my web service has a goroutine which continually pings a health check URL every few seconds.

And today, that http Get request failed, returning an error. 

So here's the code that failed:

        resp, err := http.Get(url)
        if err != nil {
            log.Println(err)
        }
        resp.Body.Close()

See if you can notice the bug here. Yes, the problem is that when err is not nil, the resp can be a nil pointer. So doing resp.Body.Close() will cause a panic. Which is what happened.

The correct thing is to return when err != nil. Do not call resp.Body.Close() when err is non-nil.


I asked GPT4 this question and it actually spotted the bug immediately:

This code appears incomplete, and there is a critical bug that could cause a program execution to panic. The issue is that http.Get(url) could fail and return a nil response. If that occurs, calling resp.Body.Close() will trigger a runtime panic because you're trying to access a property on a nil value.

You should always check whether err is nil before working with the resp object to avoid such issues. Here's a corrected version:

        resp, err := http.Get(url)
        if err != nil {
            log.Println(err)
            return
        }
        defer resp.Body.Close()

By returning from the function after logging the error, you're ensuring resp.Body.Close() isn't called when resp is nil.

Also, it's good practice to use the defer statement to close resources like this, which ensures resp.Body.Close() is called before the function returns, in any case. It helps prevent leaks of resources.


Maybe I should ask GPT4 to check over all of my code...

Monday, February 19, 2024

Wrote a tic tac toe AI

I've always wanted to write a tic tac toe AI for years and finally I decided to get off my ass and do it: https://github.com/1f604/tictactoe-ai

The actual core algorithm took me only a few minutes to code up but the scoring function was the hard part. The given perfect play every first move leads to a draw so there's no reason to prefer any particular move. But if the opponent is imperfect then some moves are better than others, since some moves will get you into a state where you can still win if the enemy makes a mistake, while other moves will get you into a state where you cannot win no matter what. So my scoring function (win_probability) calculates this by assuming the opponent picks moves randomly (with a heuristic).

Thursday, February 15, 2024

Wrote a Theseus solver

So I've been playing this iOS game called Theseus and there's a level I couldn't solve (level 80) and so I decided to write a Theseus solver to solve it for me lol. Anyway it took me less than a day to write the whole thing. Here it is:

https://github.com/1f604/theseus-solver