I started off the week approving a simple but much needed PR from Yuan which shunk the title font size and added a link to the author's blog (my favourite part.) I then went onto approve YET ANOTHER pr from Miss Lee (who has been making some nice additions to our front end apparently) which re-adds our much needed admin buttons to our front end.
Next I set my sights on the ever polite Metropass (if that is his real name). I reviewed Mo's really cool PR and left my thoughts for him to digest. I had suggested that in addition to hardcoding how long we specify our Cache ages (i.e. how long the browser should cache a piece of data vs requesting a new piece of data all over again) the developer could alternatively pass a specific value to specify how long they want to cache their stuff (the ever technical word.)
The PR also reminded me of how switch cases finally got added to Python, I remember Googling how to do them in Python during OSD600 while working on link checker program, and since Python (at the time) didn't have them, I had to instead use
if/else etc. This is kind of an ugly change if you ask me but not an entirely unwanted one.
I remember talking to Tony near the beginning of the semester and us both agreeing to work on the PWA together (though we have since diverged paths massively since I'm currently obsessed with microservices) so I'm glad to actually see it being worked on. I have to say I'm really amazed at how simple it seemed to set this up. For some reason I was picturing doing something like React Native to get this work. Nope, simply import a library and Bob's you're uncle. Amazing. I even tested it on my phone and it worked beautifully. I was in shock, truly.
Finally, I gave my comrade Ilya a brief lesson on microservices (and satellite) since he's taking over managing a microservice. I'm really excited to see where it'll head to because I can finally talk and review microservices after my experience working on one for the last few weeks. Speaking of microservice...
Feeling undeservedly accomplished for now, I went back to touching (finishing?) up the Users Microservice. I had at least two goals that I wanted to accomplish this week: properly paginate the GET route, and fully set up the users microservice for prod. First thing was first so let's dive in:
I started off by working on paginating (a fancy word for saying "give me only a slice of the cake instead of the whole cake") the GET route for the microservice. After working on the issue for a while I stumbled upon a major issue: How can I request only n number of records and know where to start at when I don't have a point of reference? I can't just pump gas into my car and know when to stop, I need some sort of point of reference. Similarly I can't just request 20 records from the DB without saying where to start and stop from. How would the query know which 20 I'm requesting? The first 20? The second? The third? Etc. Can't I to request 1 page of 20 records, another page of the following 20, and a third page of another 20 records?
Generally in these situations there's something called an offset. I can request 20 records on the 5th page and simply offset which records I want by 20 * 5, thus ensuring that I get records 100-120. But not in Firestore! Another gotcya that's slowly pushing my away from the database that I once loved. The problem with this situation is that the offset method in Firestore requests ALL records in the DB as opposed to the few that I request. This is a problem when dealing with massive databases. If I have a database with 100,000 records, and I request 20, why should I pay for the bandwidth of requesting 100,000? (Probably so Google can charge you for it, but that's neither here nor there.)
I contacted Sage Dave and asked for some advice which left both of us in a stump. The solution I came up with is simply start from user 0 and work my way up from that when requesting n users. If a user has an id of 0, I can request 10 users on page 1 and 10 users on page 2, and since I know my starting point of reference I'll easily be able to request the first 20 users.
I finished my PR and threw it up for review. As with most of my code I'm getting good reviews with a lot of language-based semantic nitpicks. JS is not my forte. I mean, I have no forte, but if I did JS would not be it. I'm really starting to enjoy it though.
Next up is making sure that the Users Microservice is ready to be deployed on production. Since our code lives inside of Docker (with traffic managed by Traefik) I have to ensure that my microservice can both receive and send signals to the other microservices as required. The complicated part of this PR is differentiating between what environment the code is currently running in, and how to respond accordingly as a result.
When the microservice is running in dev mode, we have ensure that we're using the Firebase emulator and not the actual Firebase db (as to not incur usage charges when we're simply fixing code or adding features). How do you tell which code to run when though? This is a minor problem I struggled with a lot in this PR (I think mostly it's because my knowledge of Docker, Traefik, dev vs prod, is flaky at best). But my main challenge I faced with this PR was getting the emulator to work inside of Docker's dev environment (there's a lot of minute details and things to keep in mind with this issue, so I'll try to keep this brief.)
There's currently two dev versions to this microservice, a Docker version and a local version. Think of them as one in the same entity, just with a different coat of pain. The local version works flawlessly, so why doesn't the Docker version? I simply am not able to communicate with my microservice via Docker. WHY? It's maddening! I felt my sanity slip away while working on it. I explored every Google hit I could think of before relenting and asking for help from Doc Josue. After about 2 hours of us trying to figure this out, we came across the extremely obvious (in hindsight) solution.
You need a few things to ensure that the Firebase emulator functions properly:
You have to make sure that you specify a port and address in the
You have to make sure that the
projectIds match for both the emulator and the firebase config file.
You have to make sure that the
FIRESTORE_EMULATOR_HOSTenvironment variable is PROPERLY pointing to the emulated Firebase instance in question.
If you haven't guessed it, I was declaring the Docker address incorrectly:
FIRESTORE_EMULATOR_HOST=firebase:8088. And it makes perfect sense too when you think about it.
localhost does not exist to other Docker containers, thus saying "I want you (localhost:6666) to connect to Firebase at localhost:8088" is not applicable. localhost:8088 does not exist from one container to the next. Stupid. Very stupid of me. All we had to do was specify the Docker container's network address (via
firebase:8088) and we were back in business. We also briefly tested deploying the microservice to prod using a real Firestore instance and I'm happy to report that everything works as expected!
Both PRs ended up taking much longer and being way more involved that I had thought either of them would be. I really happy that I stuck with it and managed to work through several blockers I had. I genuinely could not have done it without Doc Josue and Sage Dave as both issues required more pairs of eyes to finally figure out. Kudos to both of them. 🍻🍻🍻
In more personal news:
- Currently listening to local Windsor band Woods of Ypres
- I'm very excited that it's getting warming and I can finally start my garden up again. If anyone wants to request a specific fruit or veggie to grow now is the time, simply bring a 6 pack to share when you come to pick up the harvest. That or review my PRs. Preferably the former.
- I finally got around to watching some of Dirty Money's season 2. It's just as good as season 1 so far.