Mert Özen Further With Every Line

Blog

Mert Özen's blog posts on software development, backend, frontend, and DevOps.

Series
9 posts found
Why Messaging? From Synchronous Call Chains to Asynchronous Communication
Software Architecture PART 01

Why Messaging? From Synchronous Call Chains to Asynchronous Communication

A synchronous HTTP chain requires every dependency to be up at the same moment; dropping work on a queue breaks that temporal coupling and shields checkout from an email provider outage. Chained availability, an in-process queue with Channel<T>, the broker's role as buffer and load leveler, Web-Queue-Worker, and the price of asynchrony, with real output.

7 Nov 2026 13 min 4
Message Types: Commands, Events, and Queries; Event Notification and Event-Carried State Transfer
Software Architecture PART 02

Message Types: Commands, Events, and Queries; Event Notification and Event-Carried State Transfer

A command is imperative and goes to one receiver, an event is a past-tense fact that doesn't know its receivers, and a query expects an answer; that distinction decides a message's name, its contract owner, and its channel. An envelope with message, correlation, and causation ids, Fowler's event notification versus event-carried state transfer, and domain versus integration events, with real output.

7 Nov 2026 12 min 6
Channels: Point-to-Point Queues, Publish/Subscribe Topics, and Competing Consumers
Software Architecture PART 03

Channels: Point-to-Point Queues, Publish/Subscribe Topics, and Competing Consumers

In a point-to-point channel each message goes to exactly one consumer, in publish/subscribe each subscriber group gets its own copy, and competing consumers scale by sharing a channel. Two adapters publishing the same OrderPlaced to RabbitMQ and Kafka, exchanges/queues/bindings versus topics/partitions/consumer groups, Kafka 4.2 share groups, and choosing between a queue and a log, with real output.

7 Nov 2026 12 min 3
Delivery Guarantees: At-Most-Once, At-Least-Once, and the Truth About "Exactly-Once"
Software Architecture PART 04

Delivery Guarantees: At-Most-Once, At-Least-Once, and the Truth About "Exactly-Once"

The order of the ack and the work decides the delivery guarantee: ack first means at-most-once, work first means at-least-once; exactly-once is only possible for operations the broker itself controls, and for external side effects at-least-once plus an idempotent consumer gives effectively-once. Redelivery, publisher confirms, the three sources of duplicates, and a poison message landing in a dead-letter queue on RabbitMQ 4.4, with real output.

7 Nov 2026 12 min 4
Message Ordering and Partitioning: Where Ordering Guarantees Begin and End
Software Architecture PART 05

Message Ordering and Partitioning: Where Ordering Guarantees Begin and End

Brokers don't give a global order; Kafka partition keys, Azure Service Bus sessions, and RabbitMQ single active consumer only give order per key, and consumers should still be order-independent through version checks. Partitioning by OrderId, the hot partition a BookId key creates, keys moving when partitions are added, and the librdkafka versus Java partitioner difference, with real output on Kafka 4.2.

7 Nov 2026 12 min 3
Idempotent Consumers: What Happens When the Same Message Arrives Twice?
Software Architecture PART 06

Idempotent Consumers: What Happens When the Same Message Arrives Twice?

The reliable way to keep the same message from being processed twice is to write a stable dedup key (a MessageId or business key) to a per-consumer unique inbox table in the same transaction as the business data, and to let the unique constraint decide between concurrent duplicates. The check-then-process failure window, a crash before commit, two concurrent copies, and a two-phase record for an email that can't join the transaction, with real output on EF Core 10 and SQL Server 2025.

7 Nov 2026 15 min 3
Transactional Outbox and Inbox: Understanding and Designing Around the Dual Write Problem
Software Architecture PART 07

Transactional Outbox and Inbox: Understanding and Designing Around the Dual Write Problem

Committing to the database and separately publishing to the broker opens two failure windows; the fix is to write the message to an outbox table in the same transaction as the business data, publish it with a separate relay, and drop the relay's duplicates with an inbox on the consumer side. Dual write scenarios, polling vs CDC relays, losing messages with a watermark on PostgreSQL, and multiple relays with SKIP LOCKED, all with real output.

7 Nov 2026 16 min 3
Implementing a Saga in .NET: Persisted State Machines, Timeouts, and Compensation
Software Architecture PART 09

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.

7 Nov 2026 18 min 3
Message Contracts and Schema Evolution: CloudEvents, AsyncAPI, and Versioning
Software Architecture PART 10

Message Contracts and Schema Evolution: CloudEvents, AsyncAPI, and Versioning

A message contract is a public API between independently deployed producers and consumers; adding a field is safe, while renaming a field or adding an enum value breaks consumers silently or loudly, so changes are made with expand-contract and versioned type names. Real breakage output with System.Text.Json, the CloudEvents 1.0 envelope with the C# SDK, an event catalog validated with AsyncAPI 3.1, and schema registry compatibility modes.

7 Nov 2026 13 min 2
Blog Map