Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. Breaking Up with Google Play: Why Conversations Is Now Free (gultsch.de)
    110comments
  2. Understanding the Impact of LLM Watermarking on AI Agent Behavior (lasso.security)
    22comments
  3. Fifteen years later, the Apple Cards origin story (lexontech.org)
    18comments
  4. Revealing the details of how OpenAI agents hacked Hugging Face (swarmtraces.org)
    360comments
  5. We're gonna need a lot more mathematicians (terrytao.wordpress.com)
    293comments
  6. Plan mode is dead (aymannadeem.com)
    375comments
  7. Modern Object Pascal Introduction for Programmers – Castle Game Engine (castle-engine.io)
    8comments
  8. Reflections on 1,000 Days of Math (gmays.com)
    —discuss
  9. Floci: Locally emulating any cloud service (floci.io)
    11comments
  10. Ollaya – Ollama for open-source, Jev-style decision models (ollaya.dev)
    126comments
  11. ASML currently sells no chipmaking machines in Europe, executive says (nltimes.nl)
    72comments
  12. A single function Jev-like wrapper for LLMs, including vision models (allanrbo.blogspot.com)
    30comments
  13. Is your Postgres migration safe or not safe? (safenotsafe.dev)
    21comments
  14. 16GB iPod Nano 3G Upgrade (tuckerosman.com)
    8comments
  15. Show HN: Jev Plays Pokémon Red (jev-pokemon.vercel.app)
    91comments
  16. Parsing Expression Grammar vs. Regexes: Building Org Parser in Lisp, Export HTML (jointhefreeworld.org)
    10comments
  17. What even is an OS now? (sockpuppet.org)
    328comments
  18. Calculating atmospheric drag on satellites for a Cubesat [pdf] (osti.gov)
    6comments
  19. Ask HN: Who's still keeping a DOS machine up because the business depends on it?
    164comments
  20. Gravity seems holographic. What does that mean for reality? (quantamagazine.org)
    186comments
  21. The Murky History of Soviet-Born Tetris (mitpress.mit.edu)
    15comments
  22. Jury finds Facebook liable for deceiving users in Cambridge Analytica case (cbsnews.com)
    80comments
  23. Scientists build most accurate atomic clock (phys.org)
    17comments
  24. Fourier Analysis: Drawing Llamas with Circles (adekau.github.io)
    6comments
  25. The Copilot+ PC brand is dead (windowscentral.com)
    24comments
  26. One Month Without AI (bustikiller.com)
    128comments
  27. The far side of the Moon provides clues to a previous magnetic field (ethz.ch)
    1comments
  28. Excel now supports multiple values in a single cell (techcommunity.microsoft.com)
    153comments
  29. From Thin Air to Bootable Images: The Tine Build System (amutable.com)
    8comments
  30. Lab on a Contact Lens Can Measure Stress Through Serotonin (ieee.org)
    20comments

Is your Postgres migration safe or not safe?

73 pointsby 7h agosafenotsafe.dev
20 comments
5h agoHN ↗

Thing that bit me most wasn't the DDL itself, it was lock queuing. An ADD COLUMN is instant but if it waits behind a long read, every query behind it piles up too. Lock_timeout plus retry saved us more than any clever migration tool.

4h agoHN ↗

Agree. `lock_timeout` will go a long way in terms of damage control.

4h agoHN ↗

Nice. Integrating it on CI and catching there is still the best way/place. Having said, it doesn't work like that in practice.

4h agoHN ↗

I like the concept and I'm trying to work out if it'll be useful for me, but I just cannot get past the cookie-cutter LLM style of the landing page. A Go library doesn't need a marketing page with a seemingly unrelated artwork and call-outs like "Climb from easy to nightmare →". Put a runnable example front and centre.

5h agoHN ↗

Author here: Adding some context. I led the Postgres platform team (2019-23) at Cloudflare and we were supporting 170+ growing product teams. One of the constant asks is schema migration review. We published a lot of best practices, added CI checks however, it was still hard to catch. Also, I tried to explain the internals of how the locking (rewrite) works, but I realized most of the devs just want the answer - Is it safe or not safe to run?

Not sure if it rings a bell, the name is a reference to the Silicon Valley Jian Yang's hot dog or not hot dog app.

Also, I understand the decision of safe vs not-safe depends heavily on data/histogram and edge cases, but still quite a lot of low-hanging issues can be easily caught with a deterministic rule engine. So I ported pg_savior[1] and used sql parser from libpg-query-node[2] which compiles as WASM, so it entirely runs on the browser. No telemetry, no login. Source attached [3]

[1] https://github.com/viggy28/pg_savior [2] https://github.com/constructive-io/libpg-query-node [3] https://github.com/viggy28/safe-not-safe

4h agoHN ↗

Wow, great idea!

It's not immediately clear from the README, but is it easy to run with multiple profiles like "backwards-compatible", "revertable" (both data and schema) and "destructive" for that final clean-up in multi-staged no-downtime migrations? Basically common subsets of "safe-ness" of the schema migration queries.

I imagine it can be tuned, but I'd love this for all my projects.

And since I am currently on a project doing MS SQL (gasp), that'd be cool too ;)

I am familiar with an "is it a hot dog" app from back in the day, bit would have never made the connection :)

4h agoHN ↗

Thanks you.

Certainly, there is a lot of room to improve the README. Overall the project is very much alpha.

You're right. Currently, it's very binary. The answer is more nuanced and it should classify it based on the profiles like you mentioned.

Also, I noticed parsers for other databases that compiles to WASM. So, all running on client side.

3h agoHN ↗

This looks extremely useful.

If you continue working on this a good direction to go in would be to package it as a command line tool, so it can be integrated into testing and release processes.

5h agoHN ↗

really like the browser-only approach here - catching the obvious migration risks locally before they ever reach CI feels super useful

3h agoHN ↗

These kinds of rule-based migration safety checks are simple, but hardly complete.

The problem is that some migration safety depends on the state of the database, which isn’t represented in the DDL statement alone. For example, altering a column type is either a no-op or an exclusive locked table rewrite depending on the original type of the column.

There are other footguns that can happen if the column you’re altering is a foreign key, where multiple tables can be locked.

I went down a rabbit hole a few years ago and built a system[1] to introspect a given migration against a live schema, and actually let Postgres tell you what it’s doing[2].

It would be great to have better built-in support for this (EXPLAIN for DDL statements?), but this direction feels safer and more accurate than static rulesets.

Safety also depends on the size/activity of a table being altered (i.e rewriting an empty table is fine). Having an accurate representation of the locks and actions performed by the database lets you integrate with production metrics to actually determine real-world safety across a fleet of databases, rather than guessing.

1. https://github.com/orf/locksmith

2. https://github.com/orf/locksmith/blob/f8798c6ee92bfae10d416c...

2h agoHN ↗

The way I wished Postgres DDLs worked (at least optionally) is that you have to explicitly acquire the correct lock before a DDL statement, or it just immediately fails. Something like:

ACQUIRE ACCESS SHARE TABLE LOCK ON my_table ALTER TABLE my_table ALTER COLUMN my_column TYPE bigint

This way I _know_ that if the operation needs a stronger lock than I thought or than I'm willing to give it, it will just fail rather than locking up my database and causing unexpected downtime.

2h agoHN ↗

That’s an interesting idea but not all locks are held for the duration of the statement. A lot of them take a less intrusive lock for the whole statement and take an exclusive lock for a very short time when they finish up.

Edit: Looking this up, I’m not sure this is correct.

59m agoHN ↗

whole statement

simplified you can think of a statement outside of a transaction as starting an implicit transaction just for itself

and (normal) locks are in general hold until the end of the transaction (while also allowing re-entrance from subsequent queries on the same transaction)

practically

- there are edge cases (e.g. Advisory Locks, but in general you don't want to use them)

- you normally(^1) would want to run your pg migration as a single transaction (but there are edge cases). And in turn the OPs idea of pre-acquiring locks would be for the whole transaction anyway. Plus it was just a general idea, so the end result could be more like an "expect lock" statement maybe with some scan ahead ability then an "acquire lock".

(^1): Exceptions include certain operations which need to be in different transactions, and some painful situations where too much data is touched/changed/computed and you need a lot of very careful handling you common small-ish PG DB use-case isn't exposed to (and in turn a lot of "naive but often good enough" migration setups can't handle either...)

1h agoHN ↗

I think you could automate this with 2 transactions

- connection A, lock timeout=0, acquire unwanted lock

- connection B, lock timeout=0, run migration

- collection A, rollback

Then connection B will fail if it tries to acquire an undesirable lock since it will conflict with A. You'd be adding a very small window when you're actually holding the undesirable lock, though

48m agoHN ↗

This is essentially how my tool discovers locks for a given arbitrary DDL statement.

1h agoHN ↗

Locksmith is awesome, how am I just now discovering this?

Your comments re: database state are spot on. DDL can fail in subtle ways. It's not even enough to take a snapshot of the current state and validate; things can change under your feet.

Take adding a unique index on a column: a simple CREATE UNIQUE INDEX statement, right? But you realize it will fail if the values aren't unique already, so you run a SELECT query to confirm. Yep, all unique. Deploy the app which runs the migration on startup - fail. A non-unique key arrived in the time between your queries.

Even more fun if you CREATE UNIQUE INDEX CONCURRENTLY and a non-unique key arrives in the middle of the DDL execution.

14m agoHN ↗

I would go further than this and argue that most bugs during database migrations happen because of mismatched application behavior with the action of the migration, not because the DDL was wrong. E.g. removing something that was still being relied on by the application, or starting to backfill data to a new column before the application is fully writing it. The most insidious version of this is where one application server doesn't have it's code updated (or comes back from the dead, etc) and causes the problem.

At a previous job what I did to prevent that was to have a special DB table that would signal what capabilities the database has, and the code would read that table and compare to its own requirements. If a capability required by the database was not present in the code (e.g. code not updated for a new feature) the code would refuse to make any writes to the DB and error all incoming requests. Likewise if a capability required by the code was missing from the database (e.g. code deployed too soon and database migration not run yet) it again would refuse requests. Before setting a feature to required in the DB and preforming the migration with feature flags, we could check all known application servers were reporting compatibility with the new feature (if any were down or not reporting at the time, they will be blocked in the next step - prioritizing safety over liveness)

52m agoHN ↗

Although useful, I think migration linters like this one don't give enough peace of mind. I have maintained a zero-downtime schema migration tool for several years now that tries to cover all the different ways one can shoot oneself in the foot: https://github.com/fabianlindfors/reshape

It ensures migrations don't lock the database but maybe more importantly, it allows zero-downtime rollouts for your application as well by supporting both the old and new schema during the deployment, and automatically data between them. It also handles backfills and more that usually require multiple, separate deployments when using standard SQL commands.