Mert Özen Further With Every Line

Blog

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

Series
11 posts found #postgresql
Storage and Stateful Apps in Kubernetes: Volumes, PersistentVolumeClaims, StatefulSets and the Database Decision
DevOps PART 12

Storage and Stateful Apps in Kubernetes: Volumes, PersistentVolumeClaims, StatefulSets and the Database Decision

If several replicas must write the same files, the answer is object storage, not a PVC; ReadWriteOnce means one node, not one pod. With real output we look at emptyDir sizeLimit eviction, StorageClasses and reclaim policy, PostgreSQL 18 on a StatefulSet (including the new PGDATA path), managed DB versus operator, and the ASP.NET Core Data Protection key ring breaking across replicas.

8 Nov 2026 11 min 5
Where Migrations Fit in a Deploy: Expand-Contract, EF Core Migration Bundles and Backward-Compatible Schemas
DevOps PART 06

Where Migrations Fit in a Deploy: Expand-Contract, EF Core Migration Bundles and Backward-Compatible Schemas

Safely splitting a column while two versions run side by side takes three deploys: add and dual-write, switch to the new columns, remove the old one. Real runs on PostgreSQL with 300,000 rows: v1 and v2 working together on one schema, the transaction error of a CONCURRENTLY index, deadlocks in parallel bundles because Npgsql's migration lock is tied to the transaction, 135 ms batches instead of an UPDATE locking for 8 s, and a review gate that stops DROP COLUMN.

8 Nov 2026 13 min 6
Jobs in GitHub Actions: needs, matrix, concurrency, timeouts and Service Containers
DevOps PART 04

Jobs in GitHub Actions: needs, matrix, concurrency, timeouts and Service Containers

Jobs run in parallel by default; needs builds a DAG, and everything depending on a failed job is skipped. We split the Bookstore CI into format, unit-test (OS matrix), integration-test (PostgreSQL 16/17/18 service container), web-build and publish jobs and run it with act, covering include/exclude, fail-fast, max-parallel, concurrency, timeout-minutes, continue-on-error and the service command/entrypoint keys from April 2026.

8 Nov 2026 11 min 5
Long-Running and Batch Jobs: Chunking, Checkpoints and Surviving Deploy Interruptions
Backend PART 09

Long-Running and Batch Jobs: Chunking, Checkpoints and Surviving Deploy Interruptions

Doing a 2-million-row price update in a single UPDATE made a request updating the same row wait 1.9 seconds; with 20,000-row chunks it waited 4 ms. A job that commits each chunk in the same transaction as its checkpoint row stopped at row 800,000 during a deploy and carried on from there after restarting. Hangfire protects long jobs with a sliding invisibility timeout; if the process dies, the job moves to another worker once that window passes.

8 Nov 2026 11 min 5
Scheduling with Quartz.NET 4: Jobs, Triggers, Persistent JobStore and Clustering
Backend PART 06

Scheduling with Quartz.NET 4: Jobs, Triggers, Persistent JobStore and Clustering

In Quartz.NET 4, jobs and triggers are separate objects, IJob returns ValueTask and takes a CancellationToken, and DI and hosting live in the core Quartz package. Two nodes sharing one PostgreSQL database form a cluster: when the executing node dies by kill -9, the other notices about 15 seconds later and reruns the RequestRecovery job with recovering=true. At startup the code definition overwrites the JobDataMap stored in the database; IgnoreDuplicates prevents that.

8 Nov 2026 11 min 5
Transactional Outbox in .NET: EF Core, a BackgroundService Relay and the MassTransit/Wolverine Outbox
Backend PART 11

Transactional Outbox in .NET: EF Core, a BackgroundService Relay and the MassTransit/Wolverine Outbox

Write the message to an outbox table in the same transaction as the business data instead of to the broker, and let a BackgroundService relay pick rows with FOR UPDATE SKIP LOCKED and publish them with confirms. A real run of two instances publishing 200 messages exactly once and returning 201 while the broker is down; why the relay is at-least-once and unordered; MassTransit bus outbox, Wolverine and CDC.

8 Nov 2026 12 min 6
System Design Case Study: Flash Sales and Ticketing
Software Architecture PART 15

System Design Case Study: Flash Sales and Ticketing

What prevents overselling in a flash sale is doing the stock check and the decrement in a single atomic step; a waiting room served from a CDN absorbs the spike, holds with a TTL manage the payment window, and expired holds return stock in the same statement. Real output with 2,000 concurrent buyers for 100 tickets: 2,000 reservations from naive code, a conditional UPDATE and optimistic concurrency, plus payment timeouts and bot defense.

8 Nov 2026 13 min 5
Working with an Event Store: Append, Optimistic Concurrency, and Streams with Marten and PostgreSQL
Software Architecture PART 06

Working with an Event Store: Append, Optimistic Concurrency, and Streams with Marten and PostgreSQL

An event store's core contract is appending to a stream only while it is at the expected version; Marten provides this on PostgreSQL with a unique index on (stream_id, version) and FetchForWriting. Setting up Marten 9, StartStream/Append, wiring a decider to FetchForWriting, a race between two writers, stream id strategies, KurrentDB versus your own table, and event names that break under a Turkish culture.

7 Nov 2026 16 min 4
A Separate Read Model: Materialized Views, Synchronization, and Living with Eventual Consistency
Software Architecture PART 03

A Separate Read Model: Materialized Views, Synchronization, and Living with Eventual Consistency

A separate read model stores the screen's row precomputed from domain events; updated in the same transaction it stays immediately consistent, updated asynchronously in a separate database you have to live with eventual consistency. Inline projections, PostgreSQL materialized views, an asynchronous projector with a checkpoint, waiting on a position for read-your-own-writes, idempotent updates and a full rebuild, with real output.

7 Nov 2026 14 min 5
CQRS in a Single Database: Aggregates on the Write Side, Projections on the Read Side
Software Architecture PART 02

CQRS in a Single Database: Aggregates on the Write Side, Projections on the Read Side

CQRS in a single database means saving the aggregate through EF Core's change tracker on the write side and projecting from the same tables on the read side without ever touching the aggregate. What PlaceOrder and CancelOrder should return, a separate flat read DbContext, Dapper over a SQL view, and having PostgreSQL enforce that queries don't change state with read-only transactions, with real SQL and the 25006 error.

7 Nov 2026 14 min 5
Stored Procedures with Dapper: Output, Return Value and the Auto-Detection Trap of 2.1.11
Database PART 12

Stored Procedures with Dapper: Output, Return Value and the Auto-Detection Trap of 2.1.11

SQLite has no stored procedures, so we move to SQL Server in docker: CommandType.StoredProcedure, output and return values with DynamicParameters, how SET NOCOUNT affects Execute, single-word commands mistaken for procedures since 2.1.11, and the function vs procedure difference in PostgreSQL.

6 Nov 2026 10 min 16
Blog Map