5 AWS Services, 5 Different Approaches to Idempotence
Comparing idempotence in CloudFormation UpdateStack, AWS Backup StartBackupJob, and EC2, RDS and Aurora Start/Stop
Published May 23, 2025
If your application uses EventBridge, SQS queues, AWS Lambda functions, Step Functions, or other constructs from the realm of modern, "loosely-coupled" software architecture, you can make it faster, simpler, and more reliable by attending to idempotence. There is less overhead, less checking, once you can guarantee that repeating an operation won't change the result. If the AWS operations that underly your application are idempotent, it is even easier to make your own code idempotent.
In the process of writing and refining github.com/sqlxpert/lights-off-aws , a tool to cut costs by temporarily stopping or deleting expensive resources based on cron schedules in resource tags or stack tags, I've become all too familiar with the different ways in which 5 core AWS services approach idempotence. The services were launched at different times, and it shows.
Operations | Idempotence Mechanism | Exception, Error Code | Token (Restrictions) |
---|---|---|---|
EC2: | |||
StartInstances StopInstances | Built-in | ||
RDS: | |||
StartDBInstance StopDBInstance | Not idempotent | Invalid…StateFault Invalid…State | |
Aurora: | |||
StartDBCluster StopDBCluster | Check error message after | Invalid…StateFault Invalid…StateFault | |
CloudFormation: | |||
UpdateStack | Set token before | ClientRequestToken (≤128 letters, numbers, hyphens) | |
AWS Backup: | |||
StartBackupJob | Set token before | IdempotencyToken (no restrictions) |
EC2 is the oldest of the 5 services covered.
StartInstances
and StopInstances
are idempotent. If I try to start a compute instance that is already running, my request succeeds. The dynamic response mentions that the instance was already running at the exact time of my request, in case I need to know.RDS was built on EC2, but
StartDBInstance
and StopDBInstance
are not idempotent. If I try to start a database that is already running, I get an error. The exception name is InvalidDBInstanceStateFault
but the error code is InvalidDBInstanceState
— a bug waiting to happen! The only thing the long, mostly static error message doesn't tell me is that the database was already running (available
) at the exact time of my request. I don't know whether to ignore the error (because my start request is indeed a harmless repeat) or take it seriously (in case the database is in a bad state and cannot be started). Keep in mind that relying on a separate status check would create a race condition.Aurora is RDS's new and improved cousin.
StartDBCluster
and StopDBCluster
feature a consistent exception name and error code, InvalidDBClusterStateFault
. More importantly, the dynamic error message mentions that the database was already running (available
) at the exact time of my request. Knowingly ignoring the error achieves idempotence after the fact.CloudFormation predates Aurora. If I add a fixed token,
UpdateStack
is idempotent: repeated requests succeed and CloudFormation acts only on the first request. ClientRequestToken
is limited to 128 alphanumeric characters and hyphens. Because idempotence often applies during a known time interval, and because CloudFormation displays the token in the AWS Console (in the stack events list), a human-readable "extended" ISO 8601-standard time string would be ideal. Instead, we have to settle for the cryptic "basic" form, T1510Z
instead of T15:10Z
, for example.Arbitrary lexical restrictions that make token values harder for humans to interpret are frustrating, but there is also a semantic problem lurking below this approach to idempotence. WhatUpdateStack
idempotence case cannot be resolved with a token? Feel free to discuss in the comments. Hint: review the EC2StartInstances
example, above.
AWS Backup is the newest of the 5 services covered.
StartBackupJob
follows the same approach as CloudFormation UpdateStack
, but the token is named IdempotencyToken
and no specific limits are placed on length or permitted characters.These 5 AWS services take different approaches to idempotence. EC2, the oldest of the 5, and AWS Backup, the newest, handle idempotence very well. RDS
StartDBInstance
and StopDBInstance
are not idempotent. The Aurora equivalents, StartDBCluster
and StopDBCluster
, put extra work on the user — and CloudFormation UpdateStack
does, too, though there's no warning in the UpdateStack documentation.If we consider EC2StartInstances
/StopInstances
, AuroraStartDBCluster
/StopDBCluster
and AWS BackupStartBackupJob
as examples of three basic approaches to idempotence, which two approaches are semantically equivalent? Would any one approach be sufficient to make all of the operations covered in this article idempotent? If not, what makes one operation or pair of operations special? Feel free to discuss your ideas in the comments.
Inconsistencies are expensive! As AWS users, we have to discover them, sometimes by trial and error, then write extra code to work around them, and then fix the extra bugs that result. Although it's impractical to change existing, widely-used APIs, I hope AWS will standardize its approaches to idempotence in new services and features. I suggest ways to prevent inconsistent software designs and implementations within our own organizations, in the second half of a less technical version of this article, on LinkedIn…