O Conceito de Idempotência
Qual a importância da Idempotência?
Implementando Idempotência
Exemplo em Kotlin com Spring
Executando o projeto
- Clone o repositório
git clone https://github.com/daanrsantiago/idempotency-example- Navegue até o diretório do projeto:
cd idempotency-example- Compile o projeto usando o gradle
./gradlew build- Execute o docker compose
docker compose up- Execute a aplicação
java -jar build/libs/idempotency-example-0.0.1-SNAPSHOT.jarImplementação dos Recursos Publication e User
Publication.kt
package dev.danielsantiago.idempotency.model
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType.AUTO
import jakarta.persistence.Id
import java.time.LocalDateTime
@Entity
data class Publication(
@Id
@GeneratedValue(strategy= AUTO)
var id: Long? = null,
var title: String,
var content: String,
val creationDate: LocalDateTime = LocalDateTime.now()
)
User.kt
package dev.danielsantiago.idempotency.model
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType.AUTO
import jakarta.persistence.Id
import jakarta.persistence.Table
@Entity
@Table(name = "users")
data class User(
@Id
@GeneratedValue(strategy = AUTO)
var id: Long? = null,
val name: String,
val age: Int,
@Column(unique = true)
val cpf: String
)
Publication.kt
package dev.danielsantiago.idempotency.controller
import ...
@RestController
@RequestMapping("/publication")
class PublicationController(
val publicationRepository: PublicationRepository,
val template: RedisTemplate<String, String>
) {
val PREFIX = "publication:idempotency:"
...
@PostMapping()
fun publishPublication(@RequestBody body: PublicationRequest): ResponseEntity<Publication> {
val publishedPublication = publicationRepository.save(
Publication(
title = body.title,
content = body.content
)
)
return ResponseEntity.status(CREATED).body(publishedPublication)
}
@PostMapping("/idempotent")
fun eventualIdempotency(@RequestBody body: PublicationRequest): ResponseEntity<Publication> {
if(template.opsForValue().setIfAbsent(PREFIX + body.hashCode(), "1", Duration.ofMinutes(1))!!) {
val publishedPublication = publicationRepository.save(
Publication(
title = body.title,
content = body.content
)
)
return ResponseEntity.status(CREATED).body(publishedPublication)
} else {
return ResponseEntity.status(UNPROCESSABLE_ENTITY).build()
}
}
...
}
