The AMQP Property the Broker Vetoed
A caller-identity feature added at 21:10, disabled at 22:31 and deleted four days later - and the residue is a gateway that carries no caller identity into a message at all.
Newest first, grouped by year. Search or filter by topic.
A caller-identity feature added at 21:10, disabled at 22:31 and deleted four days later - and the residue is a gateway that carries no caller identity into a message at all.
One YAML key turns an HTTP route into a message publisher - and between BasicPublish returning and the gateway writing 202 there is nothing at all.
Eleven parts of reading one commit. Inflow's dependency-inversion boundary survived a real transport swap intact - and everything ambient that used to travel with a message did not. The retrospective, the ledger, and what I would take from it.
Inflow's transport seam is one method wide and genuinely transport-agnostic, but it has exactly one implementation and no default. A four-line Null Object and one if statement would have turned a fork in the road into a configuration flag.
The extracted Customers service ships one EF migration that creates three empty tables in a brand-new database. Nothing dual-writes, nothing backfills, nothing reconciles - and the only path that repopulates the service is events that have not happened yet.
Inflow's monolith failed startup when two modules disagreed about the shape of a shared event. The microservices branch deletes that check from exactly the boundary that became remote - and it turns out the deletion was not optional.
Inflow did not delete the module it extracted. It copied sixty-odd files into a new service, flipped one boolean, and left both copies in the solution - a decision that is better than it first looks and costs more than it first looks.
Inflow publishes a message id onto the wire, RabbitMQ delivers it, and the subscriber never reads it. The response was a guard that skips deduplication rather than one that reads the id - and the correlation id that does cross is a fresh random Guid.
On Inflow's microservices branch the wire address of every event is derived from the CLR type name, computed independently on both sides of the network. Two records in two assemblies match only because someone spelled them the same way.
Inflow's queue template would have given three modules one shared queue and turned publish-subscribe into competing consumers. Eight hand-written string literals in three projects are what prevent it - and forgetting a ninth would not be an error, just silence.
The whole RabbitMQ adapter that makes Inflow's monolith talk to an extracted service is five files in one folder. Reading them shows how small a real transport swap can be - and where the fan-out quietly narrowed from every handler to exactly one.
Inflow's IMessageBroker is byte-identical on the monolith branch and the microservices branch, and not one handler, saga or controller changed to accommodate a real broker. That is a genuine result - and the reason it worked is also the reason for everything that goes wrong later.
Ask git what an extraction cost and it will confidently give you the wrong number. Inflow's microservices branch diffs at 161 files against master - the honest figure is 108, and the fifty-three-file gap is a lesson in how migration retrospectives get fabricated.
Every modular monolith promises you can extract a module later. Inflow has a branch where someone actually did it - one module lifted into its own process behind a gateway and a real broker. This series reads that branch line by line.
Trill ships Jaeger, Prometheus, Grafana, Seq, Consul and Vault, and contains no circuit breaker, no dead-letter queue, no health check and no alert rule - the closing retrospective on what this estate gets right, what it does not, and when not to build a system this way.
Trill contains a complete synchronous integration architecture - typed gRPC and HTTP clients, a live gRPC server, generated stubs, an options class - that was built, wired and then disabled by commenting out three lines across two repositories.
Trill has no shared contracts package - every consumer re-declares the publisher's event class by hand. Diffing all fourteen duplicated contracts shows exactly two have drifted, and the ratio is what makes copy-paste governance feel safe until it isn't.
Trill's ad-publication saga implements Compensating Action in five overrides and can reach none of them - the rejection events it subscribes to carry no correlating id, their handlers return Task.CompletedTask, and no handler ever throws.
Trill's push service checks its cancellation token after dequeuing rather than before, so a disconnected client wins one more message from the shared queue and destroys it - and the Blazor client that consumes the stream never reconnects.
Trill's push service gates stories on a visibility window and silently discards anything scheduled for later - a Message Filter where a delay was intended, with no scheduler, no delay queue and no re-delivery anywhere in the estate.
Trill's push service fans stories out with a single System.Threading.Channels queue - which means every connected browser competes for the same message instead of all receiving it, and the class name is plural while the field is not.
Trill's gateway declares an authenticatedUser authorisation policy exactly once and attaches it to nothing - and its identity middleware returns early when the Authorization header is absent, so a caller with no token at all can publish commands onto the estate's message bus.
Trill's gateway authenticates the caller, parses the subject claim out of the JWT and writes it into the request body as a userId - a Content Enricher at the edge that explains the whole estate's API shape, and carries four defects in fifty lines.
Trill's gateway parses the story id out of the URL, boxes it into a route-value dictionary, and uses the result as a boolean - so the synchronous and asynchronous versions of the same operation have different contracts and only one of them honours the URL.
Trill's API gateway turns HTTP posts into AMQP messages using eighty lines of middleware, a route template and a raw JSON blob - it publishes onto the estate's bus with zero compile-time knowledge of any contract, which is the exact inverse of what every other repo does.