Here's what I got done this week:
* Hired a marketing agency
* Published my April retrospective
* Published new TinyPilot landing page
If I'm making $58k/month in revenue, how can I be losing $3k/month overall? Come with me to my April retrospective, where I explore what's holding TinyPilot back from profitability. https://mtlynch.io/retrospectives/2022/05/
I'm so excited about this!
For the past year I've been building all of my apps using Fly and Litestream, so it's awesome to see them come together as a single company.
Breaking: Litestream is now part of http://Fly.io!
Do you like SQLite? Do you like streaming replication? No? Read @benbjohnson’s new post on the http://Fly.io blog anyway: https://fly.io/blog/all-in-on-sqlite-litestream/
If your website's SSL certificate was issued in 2020, it may have stopped working in Chrome today (with the error NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED). Fix is to get a new certificate from your CA.
Use this tool to check if your site is affected: https://sslmate.com/labs/ct_policy_analyzer
The results are in for April:
My programmatic SEO experiment is killing it 6 months in! Over 2k visitors in April alone. That's +226% from last month!
All the nitty gritty details in my April retrospective: https://allisonseboldt.com/april-2022/
Creating the index is a one-line fix, and it doesn't have the drawback my original PR did of storing a redundant copy of the file size. https://github.com/mtlynch/picoshare/pull/230/files
Update! @wmertens and @dholth showed me a simpler way to achieve the same performance without storing the file size redundantly. Creating an index achieves the same thing.
Enjoyed this post about disagreeing constructively. I like Cory's distinction between "range of opinions I personally hold," and "range of opinions I find it reasonable for others to hold," and how they shouldn't be identical most of the time.
After a heated disagreement with a friend went way better than expected, I figured out what saved it, and packaged it up into a long-ass essay.
Maybe it will help everyone on here be just …
The last tricky part was writing a SQL migration to populate the sizes of files that were uploaded and stored in the DB before this change. I've never written an update that derives from other data in the DB before, but it wasn't too hard.
And we have a winner! For the same 1.1 GB file, latency dropped from 9s to 9ms, a 100x speedup.
Next, I tried storing the file size along with the file metadata
This surprised me, and I still don't have a good explanation for it. It's 3,708 rows, so it doesn't seem like it should take SQLite *that* long to calculate the SUM of 3708 values.
I'm guessing the large blob in each row slows down the query even though we don't read it.
I tried running the SQL on its own, and it took 743 ms
Storing the chunk size worked, and it brought the latency down from 9s to 839ms, a 10x performance boost.
But 839ms to calculate the size of a single file was still pretty slow...
But based on the 9s latency, calculating sizes on the fly wasn't going to work.
My first thought was to store the chunk size alongside the blob in the table containing file data. That had the advantage of keeping size close to the data it described.
I had specifically avoided storing the file size in my SQLite DB because it was redundant. The raw data is there, so we can always derive the size. It shouldn't be something we store independently.
I checked the SQLite docs. They didn't explicitly say that LENGTH reads the full blob data, but it suggested for strings, it calculated length on the fly by looking for the first null byte. I'm assuming for BLOB types, SQLite iterates through the full contents of the column
Solo developer. Lover of unit tests. Builder of TinyPilot. ex-Google, ex-Microsoft
Michael Lynch's personal Mastodon instance