Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Client Version Migrations: RabbitMQ.Client 6→7 (IModel to IChannel) and MassTransit 8→9
Moving to RabbitMQ.Client 7 gave 5 compiler errors on the first build and 10 more on the second; the real risks are the ones the compiler misses: body lifetime, timeouts becoming cancellations and concurrency. Plus RabbitMQ 4.x rejecting mirroring policies, queue type mismatches, the AMQP 1.0 client, MassTransit 9 refusing to start without a license, v8 support ending on 31 December 2026, and the old Service Bus SDK mapping.
Testing Message Queue Code: Testcontainers, the MassTransit Test Harness and Contract Tests
Unit test the logic apart from the broker, test broker behavior against a real RabbitMQ with Testcontainers, and wait with signals and bounded polling instead of Task.Delay. The MassTransit test harness, the inactivity cost of negative asserts, a Total→TotalAmount rename silently turning into 0 under default JSON options, and the Microsoft.Testing.Platform setting xUnit v3 needs on .NET 10.
Idempotent Consumers and the Inbox: When the Same Message Arrives Twice
Stop a message from being processed twice with a unique constraint in the database, not with a check: write an inbox row keyed by MessageId in the same transaction as the business data, or apply ON CONFLICT to the business key. A real run of check-then-act issuing two invoices, inbox and upsert on PostgreSQL, side effects, dedupe cleanup and the MassTransit inbox.
Retry and Redelivery in Consumers: Immediate, Delayed and Exponential Backoff
Handle transient failures with a short in-memory retry and longer waits through the broker; never retry permanent failures, send them to the DLQ. Real output shows nack-requeue looping 8036 times in 5 seconds on RabbitMQ 4.4, TTL + DLX wait queues, the quorum queue's built-in delayed retry, scheduled retry in Service Bus, Kafka retry topics and MassTransit UseMessageRetry.
Messaging with MassTransit: Consumers, Publish/Send and Broker Topology — v9 Licensing and Alternatives
MassTransit takes over connections, acks, serialization and topology, reducing a consumer to a single IConsumer<T>; the price is its own exchange conventions, an envelope format and, in v9, a commercial licence. We move Billing to MassTransit 8.5.12, show publish vs send, the resulting RabbitMQ topology and the envelope, see v9 refuse to start without a licence, and build a decision table across v8, Wolverine, Rebus, NServiceBus and Brighter.
Implementing a Saga in .NET: Persisted State Machines, Timeouts, and Compensation
To make a saga reliable in .NET you store its state in a table found by correlation id and guarded by a concurrency token, leave the decision to a pure switch expression over (step, message) pairs, write commands to an outbox in the same transaction, and give every waiting step a timeout tied to that step. A lost payment reply, a timeout race, a late payment and a failed refund with EF Core and SQLite and real output; the same saga in MassTransit 8 and Wolverine, with license notes.