Service objects: idempotency
This course covers idempotency in Rails service objects: making an operation safe to run more than once with the same arguments. It starts with the concept and its three levels, then shows how double-clicks, job retries, webhook replays and race conditions create duplicates. Later lessons cover idempotency keys, UNIQUE indexes, ON CONFLICT inserts and the constraint-and-rescue pattern. The course then combines them into a three-step service with a Result object. It applies them to background jobs and webhooks and ends with RSpec tests that check nothing duplicates.
What you'll learn
- ✓The meaning of idempotency and its three levels: natural, constraint-based and key-based
- ✓How double-clicks, job retries, webhook replays and races create duplicate records
- ✓How to design idempotency keys and store them in a table or on the record
- ✓UNIQUE and partial indexes, insert, upsert and ON CONFLICT in PostgreSQL
- ✓A three-step service object pattern that returns a Data.define Result
- ✓RSpec tests for duplicate calls, race paths, keys and side effects
What is idempotency?
You walk into a dark room and flip the light switch up. The light turns on. You flip it up again, and nothing changes, because the light was already on. You can flip it up fifty times and the result is the same: the light is on.
Read the full lesson free →Curriculum
7 lessonsWhat is idempotency?
Defines idempotency, contrasts absolute and relative operations, covers HTTP methods and introduces the three levels of idempotency.
The cost of non-idempotent code
Shows how double-clicks, job retries, webhook replays and the find_or_create_by race create silent duplicates in Rails.
Idempotency keys
Explains idempotency keys, a table of processed keys, keys stored on the XP record, and who generates them.
Database-level idempotency
Uses UNIQUE and partial indexes, constraint and rescue, and ON CONFLICT inserts and upserts to block duplicate rows.
Idempotent service objects in Rails
Combines a check, create! and rescue RecordNotUnique into one service object that returns an immutable Data.define Result.
Idempotency in background jobs & webhooks
Covers jobs that run again, retry_on, webhook replays, stable keys built from arguments and the event log pattern.
Testing idempotent services
Writes RSpec tests for duplicate calls, the RecordNotUnique path, idempotency keys, side effects and consistent Result objects.