<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: brandur-leach</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/brandur-leach.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2022-07-19T20:40:06+00:00</updated><author><name>Simon Willison</name></author><entry><title>Soft Deletion Probably Isn't Worth It</title><link href="https://simonwillison.net/2022/Jul/19/soft-deletion-probably-isnt-worth-it/#atom-tag" rel="alternate"/><published>2022-07-19T20:40:06+00:00</published><updated>2022-07-19T20:40:06+00:00</updated><id>https://simonwillison.net/2022/Jul/19/soft-deletion-probably-isnt-worth-it/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/soft-deletion"&gt;Soft Deletion Probably Isn&amp;#x27;t Worth It&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Brandur argues that soft deletion—where you delete records by populating a “is_deleted” or “deleted_at” column in your table—isn’t worth the additional complexity and risk it adds to other database queries. Instead, he suggests having a separate deleted records table which records the deleted data in a JSON blob—allowing you to review and recover it manually if necessary, and giving you an easy way to expire deleted records that have exceeded your retention policy.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="databases"/><category term="brandur-leach"/></entry><entry><title>Heroku: Core Impact</title><link href="https://simonwillison.net/2022/May/16/heroku-core-impact/#atom-tag" rel="alternate"/><published>2022-05-16T04:24:50+00:00</published><updated>2022-05-16T04:24:50+00:00</updated><id>https://simonwillison.net/2022/May/16/heroku-core-impact/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/nanoglyphs/033-heroku"&gt;Heroku: Core Impact&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Ex-Heroku engineer Brandur Leach pulls together some of the background information circulating concerning the now more than a month long Heroku security incident and provides some ex-insider commentary on what went right and what went wrong with a platform that left a huge, if somewhat underappreciated impact on the technology industry at large.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=31391272"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/heroku"&gt;heroku&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="heroku"/><category term="brandur-leach"/></entry><entry><title>Single dependency stacks</title><link href="https://simonwillison.net/2022/Feb/9/single-dependency-stacks/#atom-tag" rel="alternate"/><published>2022-02-09T18:43:55+00:00</published><updated>2022-02-09T18:43:55+00:00</updated><id>https://simonwillison.net/2022/Feb/9/single-dependency-stacks/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/fragments/single-dependency-stacks"&gt;Single dependency stacks&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Brandur Leach notes that the core services at Crunchy (admittedly a PostgreSQL hosting and consultancy company) have only one stateful dependency – Postgres. No Redis, ElasticSearch or anything else. This means that problems like rate limiting and search, which are often farmed out to external services, are all handled using either PostgreSQL or in-memory mechanisms on their servers.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=30274886"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="postgresql"/><category term="brandur-leach"/></entry><entry><title>Transactionally Staged Job Drains in Postgres</title><link href="https://simonwillison.net/2021/Dec/18/transactionally-staged-job-drains/#atom-tag" rel="alternate"/><published>2021-12-18T01:34:13+00:00</published><updated>2021-12-18T01:34:13+00:00</updated><id>https://simonwillison.net/2021/Dec/18/transactionally-staged-job-drains/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/job-drain"&gt;Transactionally Staged Job Drains in Postgres&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Any time I see people argue that relational databases shouldn’t be used to implement job queues I think of this post by Brandur from 2017. If you write to a queue before committing a transaction you run the risk of a queue consumer trying to read from the database before the new row becomes visible. If you write to the queue after the transaction there’s a risk an error might result in your message never being written. So: write to a relational staging table as part of the transaction, then have a separate process read from that table and write to the queue.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/queues"&gt;queues&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/scaling"&gt;scaling&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="postgresql"/><category term="queues"/><category term="scaling"/><category term="brandur-leach"/></entry><entry><title>Quoting Hyrum's Law</title><link href="https://simonwillison.net/2018/Aug/11/hyrums-law/#atom-tag" rel="alternate"/><published>2018-08-11T00:33:29+00:00</published><updated>2018-08-11T00:33:29+00:00</updated><id>https://simonwillison.net/2018/Aug/11/hyrums-law/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://brandur.org/fragments/go-http2"&gt;&lt;p&gt;With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://brandur.org/fragments/go-http2"&gt;Hyrum&amp;#x27;s Law&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/api-design"&gt;api-design&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="api-design"/><category term="brandur-leach"/></entry><entry><title>Scaling a High-traffic Rate Limiting Stack With Redis Cluster</title><link href="https://simonwillison.net/2018/Apr/26/redis-cluster/#atom-tag" rel="alternate"/><published>2018-04-26T18:34:25+00:00</published><updated>2018-04-26T18:34:25+00:00</updated><id>https://simonwillison.net/2018/Apr/26/redis-cluster/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/redis-cluster"&gt;Scaling a High-traffic Rate Limiting Stack With Redis Cluster&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Brandur Leach describes the simple, elegant and performant design of Redis Cluster, and talks about how Stripe used it to scaled their rate-limiting from one to ten nodes.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/rate-limiting"&gt;rate-limiting&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/redis"&gt;redis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/scaling"&gt;scaling&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/stripe"&gt;stripe&lt;/a&gt;&lt;/p&gt;



</summary><category term="rate-limiting"/><category term="redis"/><category term="scaling"/><category term="brandur-leach"/><category term="stripe"/></entry><entry><title>Touring a Fast, Safe, and Complete(ish) Web Service in Rust</title><link href="https://simonwillison.net/2018/Mar/28/web-service-in-rust/#atom-tag" rel="alternate"/><published>2018-03-28T15:47:26+00:00</published><updated>2018-03-28T15:47:26+00:00</updated><id>https://simonwillison.net/2018/Mar/28/web-service-in-rust/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/rust-web"&gt;Touring a Fast, Safe, and Complete(ish) Web Service in Rust&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Brandur’s notes from building a high performance web service in Rust, using PostgreSQL via the Diesel ORM and the Rust actix-web framework which provides Erlang-style actors and promise-based async concurrency.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/async"&gt;async&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="async"/><category term="postgresql"/><category term="rust"/><category term="brandur-leach"/></entry><entry><title>Scaling Postgres with Read Replicas &amp; Using WAL to Counter Stale Reads</title><link href="https://simonwillison.net/2017/Nov/18/scaling-postgres-with-read-replicas/#atom-tag" rel="alternate"/><published>2017-11-18T18:42:46+00:00</published><updated>2017-11-18T18:42:46+00:00</updated><id>https://simonwillison.net/2017/Nov/18/scaling-postgres-with-read-replicas/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/postgres-reads"&gt;Scaling Postgres with Read Replicas &amp;amp; Using WAL to Counter Stale Reads&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The problem with sending writes to the primary and balancing reads across replicas is dealing with replica lag—what if you write to the primary and then read from a replica that hasn’t had the new state applied to it yet? Brandur Leach dives deep into an elegant solution using PostgreSQL’s LSN (log sequence numbers) accesesed using pg_last_wal_replay_lsn(). An observer process continuously polls the replicas for their most recently applied LSN and stores them in a table. A column in the Users table then records the min_lsn valid for that user, updating it to the pg_current_wal_lsn() of the primary whenever that user makes a write. Combining the two allows the application to randomly select a replica that is up-to-date for the purposes of a specific user any time it needs to make a read.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=15726376"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/replication"&gt;replication&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/scaling"&gt;scaling&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="postgresql"/><category term="replication"/><category term="scaling"/><category term="brandur-leach"/></entry><entry><title>Redis Streams and the Unified Log</title><link href="https://simonwillison.net/2017/Nov/8/redis-streams-and-the-unified-log/#atom-tag" rel="alternate"/><published>2017-11-08T16:37:52+00:00</published><updated>2017-11-08T16:37:52+00:00</updated><id>https://simonwillison.net/2017/Nov/8/redis-streams-and-the-unified-log/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/redis-streams#rocket-rides-unified"&gt;Redis Streams and the Unified Log&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
In which Brandur Leach explores the new Kafka-style streams functionality coming to Redis 4.0, and shows an example of a robust at-least once processing architecture built on a combination of Redis streams and PostgreSQL transactions. I really like the pattern of writing log records to a staging table in PostgreSQL first in order to bundle them up in the same transaction as the originating state change, then have a separate process read them from that table and publish them to Redis.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/redis"&gt;redis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="postgresql"/><category term="redis"/><category term="brandur-leach"/></entry><entry><title>Quoting Brandur Leach</title><link href="https://simonwillison.net/2017/Nov/8/redis-streams/#atom-tag" rel="alternate"/><published>2017-11-08T16:23:55+00:00</published><updated>2017-11-08T16:23:55+00:00</updated><id>https://simonwillison.net/2017/Nov/8/redis-streams/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://brandur.org/redis-streams"&gt;&lt;p&gt;Redis streams aren’t exciting for their innovativeness, but rather than they bring building a unified log architecture within reach of a small and/or inexpensive app. Kafka is infamously difficult to configure and get running, and is expensive to operate once you do.  [...] Redis on the other hand is probably already in your stack.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://brandur.org/redis-streams"&gt;Brandur Leach&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/redis"&gt;redis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/kafka"&gt;kafka&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="redis"/><category term="kafka"/><category term="brandur-leach"/></entry><entry><title>Benefit of TEXT with CHECK over VARCHAR(X) in PostgreSQL</title><link href="https://simonwillison.net/2017/Oct/28/brandur-on-twitter/#atom-tag" rel="alternate"/><published>2017-10-28T00:59:34+00:00</published><updated>2017-10-28T00:59:34+00:00</updated><id>https://simonwillison.net/2017/Oct/28/brandur-on-twitter/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://twitter.com/brandur/status/923982980674043904"&gt;Benefit of TEXT with CHECK over VARCHAR(X) in PostgreSQL&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Brandur suggests using &lt;code&gt;email  TEXT CHECK (char_length(email) &amp;lt;= 255)&lt;/code&gt; to define a column with a length limit in PostgreSQL over &lt;code&gt;VARCHAR(255)&lt;/code&gt; because &lt;code&gt;TEXT&lt;/code&gt; and &lt;code&gt;VARCHAR&lt;/code&gt; are equally performant but a &lt;code&gt;CHECK&lt;/code&gt; length can be changed later on without locking the table, whereas a &lt;code&gt;VARCHAR&lt;/code&gt; requires an &lt;code&gt;ALTER TABLE&lt;/code&gt; with an exclusive lock.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="postgresql"/><category term="brandur-leach"/></entry><entry><title>Implementing Stripe-like Idempotency Keys in Postgres</title><link href="https://simonwillison.net/2017/Oct/27/stripe-like-idempotency-keys-in-postgres/#atom-tag" rel="alternate"/><published>2017-10-27T17:51:52+00:00</published><updated>2017-10-27T17:51:52+00:00</updated><id>https://simonwillison.net/2017/Oct/27/stripe-like-idempotency-keys-in-postgres/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brandur.org/idempotency-keys"&gt;Implementing Stripe-like Idempotency Keys in Postgres&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Having clients send “idempotency keys” with API requests in order to be able to safely retry them if something’s goes wrong is a really neat trick for making transactional APIs more robust. Here Brandur Leach talks implementation strategies.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=15569478"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/api-design"&gt;api-design&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/idempotency"&gt;idempotency&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/stripe"&gt;stripe&lt;/a&gt;&lt;/p&gt;



</summary><category term="api-design"/><category term="idempotency"/><category term="postgresql"/><category term="brandur-leach"/><category term="stripe"/></entry></feed>