What Does a 202 Actually Promise
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.
Newest first, grouped by year. Search or filter by topic.
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.
One sentence describes every failure convention in Inflow's shared framework - startup misconfiguration throws, runtime message failure is logged and dropped. The retrospective on fourteen parts of source-reading, including what to steal, what to avoid, and where this design should not go.
Inflow reads every configuration section by building and disposing an entire service provider - twenty-two of them during startup. Two of those calls do not read anything; they mutate a registry, and they only work because of how three singletons were registered.
Inflow's inbox writes a row only after the handler succeeds, which makes its own duplicate-check predicate dead code and its name wrong. It is a good Idempotent Receiver with a one-hour memory, a decorator that resolves from the wrong provider, and an orphaned brace pair.
Two booleans govern Inflow's messaging spine. Taking their product gives four behaviours - one shipped and working, two working differently, and one that throws a NullReferenceException every second forever because the component that would prevent it only exists in another cell.
Inflow ships a complete transactional outbox - table, poller, cleanup jobs, type registry - and one CreateScope() call means the outbox row commits on a different DbContext from the state change it is supposed to be atomic with.
Inflow registers every handler by assembly scan and then wraps them in decorators. Those two techniques are incompatible unless something tells the scanner to skip the decorators - and in this codebase that something is a marker attribute with no tests and no comment explaining what it prevents.
Inflow carries request identity across its async message boundary in a static AsyncLocal. The line that populates it uses null-coalescing assignment inside a long-lived loop, so every message after the first runs under the first one's correlation id, trace id and user.
Inflow's message broker is eighty-eight lines with a three-way branch, backed by an unbounded channel and a single background reader. Reading it shows where the delivery guarantee actually is - and that on shutdown, whatever is still queued is discarded without a log line.
Inflow's boot-time contract verifier is excellent and almost unused. A census of every consumer-side type copy in the estate shows four protected and fourteen not - and the two failure modes are a startup crash and a silently null property.
Inflow isolates modules by serialising every message to JSON bytes and deserialising it into the receiver's own type - once per receiver. It is the Message Translator done well, and the byte array in the signature tells you exactly which transport it was built for.
Inflow lets each module own a private copy of every event it consumes, then type-checks those copies against the producer at application start. It is consumer-driven contract testing with no broker, no schema registry and about 280 lines - and the check is weaker than the ceremony suggests.
One method in Inflow returns the third segment of a type's namespace, lower-cased. Four subsystems route on that string, and nothing anywhere validates it - a namespace rename is a silent behavioural change across the estate.
Inflow has no subscribe call and no topic string. A module receives an event by declaring a class with the same simple name, and a single attribute decides whether the delivery is allowed - with a cache that changes the decision, not just its speed.
Inflow's host knows nothing about its five modules - it finds them by scanning DLL filenames and reflecting for an interface. Reading the loader shows why the whole estate is that small, and where a missing settings file silently deletes a module.
Every modular monolith claims its modules are decoupled. Inflow proves it the only way that counts - by having no project reference between any two of them - and then has to build a whole mini-framework to make that survivable. Part 1 of a source-read through the shared layer.
Trill's monolith puts the envelope fields on the message itself, then uses one sentinel value to mean this-is-a-synchronous-call in three unrelated subsystems that never mention each other.
The tick that makes eventual consistency watchable in a console, the four-hop chain that takes twenty seconds because of it, and the DI-scope trap the estate is one refactor away from firing.
One estate showing the safe ordering five times and the unsafe one once, with the phantom-event failure traceable end to end through a webhook that never retries.
What an in-process event dispatcher actually guarantees when there is no outbox, no dead letter, no correlation id and no drain on shutdown - and the one static field the whole thing depends on.
Two events in GroupFlights have more than one subscriber, and both are where it breaks - two handlers ask "is this mine?" and two do not, in both directions.
The event interface has no members, so nothing can carry a correlation id - and three modules each rebuild the pattern as application state, one of them in a static dictionary with a TODO.
A single boolean in appsettings decides whether ModularMonolith's events run inside your HTTP request or on a background pump - and each setting fails differently. Delivery semantics, read honestly from a ternary.
ModularMonolith builds its message broker from System.Threading.Channels and one BackgroundService - a textbook Message Channel and Event-Driven Consumer in miniature, with every missing enterprise-integration pattern visible by its absence.
ModularMonolith routes events between modules by class name and converts them by JSON round-trip - a one-line Message Translator that lets modules share contracts without sharing types, at a price the next part collects.