81 karma · joined November 8, 2019
1. This is such an insane example, I don't get why would you give agents write access to your production db in the first place. Are people really doing this? I don't even have production connection urls on my laptop. Any manual statements executed against the db must be treated as a war-room situation with at least another engineer reviewing your SQL before you execute it.
2. Dropping the table could have easily caused writes to fail. Most likely there is no way to recover these writes (especially if it's from user requests), so it could have lead to loss of data. Reversing the table drop doesn't fix this issue.
- one team uses feature flag for product gating. Feature flag service goes down. Users temporarily got locked out of the features they paid for.
- one team uses feature flag for dynamic pricing by leveraging targeting rules (how hard is it to write a bunch of if else in code?). It’s evaluated against all users, even if they are not active (for analysis reasons). Feature flag service charges by MAU. We have millions of users. Our feature flag service bill is now 6 digits per year.
- one team uses feature flag as literal json store instead of a proper db (god knows why). Someone updated the value but the “schema” is wrong. Shit breaks.
> They got D1 (SQLite serverless), Durable Objects with their own SQLite, KV, R2, Queues, and Hyperdrive to speed up external Postgres or MySQL.
Maybe it's just me, but I don't see this as confusing:
- D1 is SQLite on cloud, their go-to relational database
- Durable object is the cousin of durable execution (via actor model instead of saga)
- KV is for caching like Redis (sub-ms read latency)
- R2 is S3, R2 SQL is Iceberg + Athena (for OLAP queries)
- Queue is SQS
- Hyperdrive is bridge to allow CF worker to use native Postgres/MySQL driver (since v8 isolate cannot maintain persistent connection)
I've built some stuff on top of CF, and the data ecosystem is actually useful.
- ClickHouse focuses on traditional CDC (ClickPipes) and just make it blazingly fast
- Databricks leans on their unified storage architecture (LTAP) to avoid copying data (though you can argue there is still a copy in the cache)
- Snowflake uses a data mirroring CDC as extension so it runs directly on Postgres
I'm still waiting for a Postgres provider to just let me mirror data directly to Iceberg, so I can plug in my own stateless query engine.
I can see the appeal for pgrust for smaller teams who need analytics, and don't want to deal with having to ETL to something like ClickHouse. But beyond a certain complexity, replicating your data to a warehouse or lakehouse _is_ the right approach and more scalable for several reasons:
- Analytics tend to be centralized, i.e. you want data from several Postgres databases spread across multiple teams to be replicated into 1 place, so people can start joining data across the entire business
- Analytics tend to fall under a different team ownership with their own set of non-technical requirements (e.g. data governance)
- Lakehouse architecture (Iceberg + [insert query engine]) is more scalable in terms of cost
- In some cases, you want to be able to swap different query engines depending on the use case, e.g. use PuppyGraph to query your data in Iceberg for fraud analysis
Nope, even if I have the ability to see the exact changes of each row, I would still add timestamps everywhere, because timestamp of row change does not equal event timestamp. For example, if I have an order table with status column, and I see a CDC event where status changed from in_progress to completed, I cannot simply assume that the CDC timestamp is the timestamp when order was completed. It's possible that the source database received the event late a few minutes late due to delay upstream, or it's backfilling some missed orders a few days ago. Having a completed_at timestamp (and a bunch of other timestamps for each order lifecycle) would eliminate any ambiguities, and your data analyst will thank you for it.
It's the same thing with row history. You cannot simply assume that your row changes are aligned with the logical history of your entity.
For example, if you know your user can change emails, and there might be events from another source that is keyed by user email (e.g. marketing-related events), then naturally you will need some sort of email_history table that has historical mapping of user id to email (you probably need it for audit purposes too). Then in this case there is no need to build SCD type 2 table of user from CDC, it's already there.
[0] https://dbos.dev
For example, with Multigres, you should be able to achieve true zero downtime major version upgrade by simply resharding [2]. With vanilla Postgres + pgBouncer, you can only achieve near-zero downtime (few seconds at most), though it's probably good enough for most use cases.
[2] https://multigres.com/docs#migrate-across-postgres-versions
[1] https://github.com/polynya-dev/pg2iceberg
[2] https://www.polarsignals.com/blog/posts/2024/05/28/mostly-ds...
I'm guessing with Neon, since their storage is a lakehouse, you get this for free.