{"id":15285387,"url":"https://github.com/transferwise/idempotence4j","last_synced_at":"2025-10-16T16:23:20.371Z","repository":{"id":38236655,"uuid":"265819821","full_name":"transferwise/idempotence4j","owner":"transferwise","description":"Lightweight library for handling idempotent actions","archived":false,"fork":false,"pushed_at":"2025-02-18T11:13:58.000Z","size":292,"stargazers_count":59,"open_issues_count":2,"forks_count":9,"subscribers_count":61,"default_branch":"master","last_synced_at":"2025-05-20T06:04:28.422Z","etag":null,"topics":["idempotency","mariadb","postgresql","side-effects","spring-boot"],"latest_commit_sha":null,"homepage":"https://github.com/transferwise/idempotence4j","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/transferwise.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-21T10:28:06.000Z","updated_at":"2025-05-20T02:27:24.000Z","dependencies_parsed_at":"2025-03-17T04:00:25.193Z","dependency_job_id":"dc84c906-9e75-4753-8821-388bc60f90ff","html_url":"https://github.com/transferwise/idempotence4j","commit_stats":null,"previous_names":[],"tags_count":76,"template":false,"template_full_name":null,"purl":"pkg:github/transferwise/idempotence4j","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transferwise%2Fidempotence4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transferwise%2Fidempotence4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transferwise%2Fidempotence4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transferwise%2Fidempotence4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/transferwise","download_url":"https://codeload.github.com/transferwise/idempotence4j/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transferwise%2Fidempotence4j/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265467594,"owners_count":23770750,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["idempotency","mariadb","postgresql","side-effects","spring-boot"],"created_at":"2024-09-30T15:04:31.016Z","updated_at":"2025-10-16T16:23:15.331Z","avatar_url":"https://github.com/transferwise.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://img.shields.io/badge/release-1.7.2-orange\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/release-1.7.2-orange\"\n            alt=\"Release version\"/\u003e\u003c/a\u003e\n\n# idempotence4j\n\nidempotence4j is a lightweight library that provides support for handling idempotent actions.\n\nAll actions are persisted to a database and it's expected that client's only going to use database master node\n to avoid any possible issues caused by the replication lag.\n\n## Overview\n\nidempotence4j provides several modules:\n\n- **idempotence4j-core** - exposes main API and defines action execution strategy\n- **idempotence4j-postgres** - `PostgreSQL` integration, defines flyway migrations, contains PostgreSQL implementation for action repository and locking\n- **idempotence4j-mariadb** - `MariaDb` integration, defines flyway migrations, contains MariaDb implementation for action repository and locking\n- **idempotence4j-metrics** - publishes metrics to `io.micrometer` registry\n- **idempotence4j-spring-boot-starter** - auto configuration for `IdempotenceService` with automatic discovery of DB implementation module\n\n\n## Usage\n\nWhen invoking idempotence service clients are expected to provide:\n\n- `actionId` - unique identifier for the current action\n- `onRetry` - function that maps persisted result of previously successful action to client result\n- `procedure` - supplier that executes the action processing logic and returns result to client\n- `toRecord` - function that maps client result to the one being persisted in the database\n- `recordType` - type of the stored record required for a later de-serialisation\n\n```java\n\n@AllArgsConstructor\npublic class ApplicationService {\n    private final IdempotenceService idempotenceService;\n    private final ResultRepository repository;\n\n    public Result execute(ActionId actionId, String args[]) {\n        Result result = idempotenceService.execute(actionId, this::byId, () -\u003e {\n            //execution logic\n            return new Result();\n        }, Result::getId, new TypeReference\u003cResultId\u003e(){});\n        return result;\n    }\n\n    private Result byId(ResultId resultId) {\n        return repository.get(resultId);\n    }\n}\n\n```\n\n## Adding idempotence4j to your build\n\nidempotence4j's Maven group ID is `com.transferwise.idempotence4j`, and its artifact ID is `idempotence4j`\n\nIf you're using **Spring Boot** here is a quick way of to add a dependency on **idempotence4j**\n\n```gradle\ndependencies {\n  implementation \"com.transferwise.idempotence4j:idempotence4j-spring-boot-starter:${project['idempotence4j.version']}\"\n  implementation \"com.transferwise.idempotence4j:idempotence4j-postgres:${project['idempotence4j.version']}\"\n  implementation \"com.transferwise.idempotence4j:idempotence4j-metrics:${project['idempotence4j.version']}\"\n}\n```\nSpring boot starter provides auto-discovery for known implementation modules\nand autowires service `Beans`. Otherwise, you can add a dependency on each module individually with core module defined as:\n\n```gradle\ndependencies {\n  implementation \"com.transferwise.idempotence4j:idempotence4j-core:${project['idempotence4j.version']}\"\n}\n```\n\n## Database modules\n\nidempotence4j comes with a set of database-specific implementations.\nFor now, the library supports only `PostgresSQL` and `MariaDB`.\n\n### PostgresSQL Module\n\nTo add PostgresSQL module to your build using Gradle, use the following:\n\n```gradle\ndependencies {\n  implementation \"com.transferwise.idempotence4j:idempotence4j-postgres:${project['idempotence4j.version']}\"\n}\n```\n\n### MariaDb Module\n\nTo add MariaDb module to your build using Gradle, use the following:\n\n```gradle\ndependencies {\n  implementation \"com.transferwise.idempotence4j:idempotence4j-mariadb:${project['idempotence4j.version']}\"\n}\n```\n\n### Flyway\n\n\u003e :exclamation: **_Important:_**  Flyway by default doesn't allow to apply \"out of order\" migrations, that means\n\u003e if you have already applied a migration with version `3`, adding migration version `1` will cause an error.\n\u003e\n\u003e Since `idempotence4j` is using a timestamp versions it can cause a number of issues, i.e. if in your project you use incremented numeric versions.\n\nPlease **only use the following configuration approach** if your flyway configuration has `flyway.outOfOrder` flag enabled, otherwise please create an exact copy of these migrations in your project flyway module.\n\n`Postgres` module contains Flyway migration definitions to keep required tables schemas up-to-date. Both `yaml` and `java` configuration examples provided below:\n\n```yaml\n\n  flyway:\n    table: flyway_schema\n    password: ${DATASOURCE_FLYWAY_PASSWORD}\n    user: ${DATASOURCE_FLYWAY_USERNAME}\n    url: ${DATASOURCE_URL}\n    locations: classpath:db/migration, classpath:db/idempotence4j/postgres\n\n```\n\n\n```java\n\n@Bean\npublic Flyway getFlyway(dataSource) {\n    var configuration = new FluentConfiguration()\n        .dataSource(dataSource)\n        .locations(\"classpath:db/migration, classpath:db/idempotence4j/postgres\")\n\n    return new Flyway(configuration)\n}\n\n```\n\n### Retention\n\nBy default action **retention** is turned off. You can enable and configure it by specifying following parameters:\n\n```yaml\nidempotence4j:\n  retention:\n    enabled: true\n    period: P0Y0M20D              # ISO-8601 format\n    purge:\n      schedule: \"*/15 * * * * ?\"  # spring cron format\n      batchSize: 150\n```\n\n\n\u003e :exclamation: **_Important:_**  Please note, if you didn't enable flyway as described in a previous section you need first to define required for `db-scheduled` tables in your schema\n\n### Metrics\n\nEach action execution collects and publishes metrics. **idempotence4j-metrics** module provides default `io.micrometer` integration and publishes following metrics:\n\n- idempotence4j.executions - **counter** with a set of tags {`type`, `client`, `outcome`}\n- idempotence4j.executions.retries - **counter** with a set of tags {`type`, `client`}\n- idempotence4j.execution.latency - **timer** with a set of tags {`type`, `client`, `outcome`}\n\nWe also provide a common `grafana` dashboard [component](https://github.com/transferwise/grafana-dashboards/blob/master/dashboards/src/components/idempotence4j/actions.libsonnet) that you can include into your provisioned dashboard.\n\n### Roadmap\n\n- Non-transactional execution strategy\n- Payload schema evolution\n- Result payload compression\n- Redis module\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransferwise%2Fidempotence4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftransferwise%2Fidempotence4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransferwise%2Fidempotence4j/lists"}