{"id":21231385,"url":"https://github.com/trendyol/jdempotent","last_synced_at":"2025-04-05T01:05:56.928Z","repository":{"id":40278312,"uuid":"314309989","full_name":"Trendyol/Jdempotent","owner":"Trendyol","description":"Make your consumer, API, etc. idempotent easily.","archived":false,"fork":false,"pushed_at":"2025-02-03T11:18:19.000Z","size":985,"stargazers_count":100,"open_issues_count":16,"forks_count":25,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-05T01:05:52.358Z","etag":null,"topics":["couchbase","idempotency","idempotent-consumer","idempotent-kafka","idempotent-rabbitmq","redis","transactional-consumer"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Trendyol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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-11-19T16:44:30.000Z","updated_at":"2025-04-04T03:42:24.000Z","dependencies_parsed_at":"2024-12-29T11:10:28.677Z","dependency_job_id":"e25bdf72-4f4c-4896-be98-56acaca84416","html_url":"https://github.com/Trendyol/Jdempotent","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Trendyol%2FJdempotent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Trendyol%2FJdempotent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Trendyol%2FJdempotent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Trendyol%2FJdempotent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Trendyol","download_url":"https://codeload.github.com/Trendyol/Jdempotent/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247271528,"owners_count":20911587,"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":["couchbase","idempotency","idempotent-consumer","idempotent-kafka","idempotent-rabbitmq","redis","transactional-consumer"],"created_at":"2024-11-20T23:46:40.097Z","updated_at":"2025-04-05T01:05:56.908Z","avatar_url":"https://github.com/Trendyol.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jdempotent\n\n[![Release Jdempotent](https://github.com/Trendyol/Jdempotent/actions/workflows/jdempotent-spring-boot-redis-starter.yml/badge.svg)](https://github.com/Trendyol/Jdempotent/actions/workflows/jdempotent-spring-boot-redis-starter.yml)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"examples/logo.jpg\"\u003e\n\u003c/p\u003e\n\n# Goal of this Jdempotent-spring-boot-starter\n\nMake your endpoints idempotent easily\n\n# Usage\n\n1. First of all, you need to add a dependency to pom.xml\n\nFor Redis:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.trendyol\u003c/groupId\u003e\n    \u003cartifactId\u003eJdempotent-spring-boot-redis-starter\u003c/artifactId\u003e\n    \u003cversion\u003e1.1.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\nFor Couchbase:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.trendyol\u003c/groupId\u003e\n    \u003cartifactId\u003eJdempotent-spring-boot-couchbase-starter\u003c/artifactId\u003e\n    \u003cversion\u003e1.1.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n2. You should add `@IdempotentResource` annotation to the method that you want to make idempotent resource, listener etc.\n\n```java\n@IdempotentResource(cachePrefix = \"WelcomingListener\")\n@KafkaListener(topics = \"trendyol.mail.welcome\", groupId = \"group_id\")\npublic void consumeMessage(@IdempotentRequestPayload String emailAdress) {\n    SendEmailRequest request = SendEmailRequest.builder()\n            .email(message)\n            .subject(subject)\n            .build();\n\n    try {\n        mailSenderService.sendMail(request);\n    } catch (MessagingException e) {\n        logger.error(\"MailSenderService.sendEmail() throw exception {} event: {} \", e, emailAdress);\n\n        // Throwing any exception is enough to delete from redis. When successful, it will not be deleted from redis and will be idempotent.\n        throw new RetryIdempotentRequestException(e);\n    }\n}\n```\n\nIf want that idempotencyId in your payload. Put `@JdempotentId` annotation that places the generated idempotency identifier into annotated field.\nCan be thought of as @Id annotation in jpa.\n\n```java\npublic class IdempotentPayload {\n   @JdempotentId\n   private String jdempotentId;\n   private Object data;\n}\n```\n\nYou might want to handle the name of the field differently to ensure idempotency. Just use @JdempotentProperty annotation needs to get the field name differently and generate the hash inspired by jackson (@JsonProperty annotation)\n\n```java\npublic class IdempotentPayload {\n   @JdempotentProperty(\"userId\")\n   private String customerId;\n   private Object data;\n}\n```\n\n\n3. If you want to handle a custom error case, you need to implement `ErrorConditionalCallback` like the following example:\n\n```java\n@Component\npublic class AspectConditionalCallback implements ErrorConditionalCallback {\n\n    @Override\n    public boolean onErrorCondition(Object response) {\n        return response == IdempotentStateEnum.ERROR;\n    }\n    \n    public RuntimeException onErrorCustomException() {\n        return new RuntimeException(\"Status cannot be error\");\n    }\n\n}\n```\n\n4. Let's make the configuration:\n\nFor redis configuration:\n\n```yaml\njdempotent:\n  enable: true\n  cache:\n    redis:\n      database: 1\n      password: \"password\"\n      sentinelHostList: 192.168.0.1,192.168.0.2,192.168.0.3\n      sentinelPort: \"26379\"\n      sentinelMasterName: \"admin\"\n      expirationTimeHour: 2\n      dialTimeoutSecond: 3\n      readTimeoutSecond: 3\n      writeTimeoutSecond: 3\n      maxRetryCount: 3\n      expireTimeoutHour: 3\n```\n\nFor couchbase configuration:\n\n```yaml\njdempotent:\n  enable: true\n  cryptography:\n    algorithm: MD5\n  cache:\n    couchbase:\n      connection-string: XXXXXXXX\n      password: XXXXXXXX\n      username: XXXXXXXX\n      bucket-name: XXXXXXXX\n      connect-timeout: 100000\n      query-timeout: 20000\n      kv-timeout: 3000\n```\n\nPlease note that you can disable Jdempotent easily if you need to. \nFor example, assume that you don't have a circuit breaker and your Redis is down.\nIn that case, you can disable Jdempotent with the following configuration:\n\n\n```yaml\n  enable: false\n```\n\n```java\n@SpringBootApplication(\n      exclude = { RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class }\n)\n```\n\n## Performance\n\nAs it is shown in the following image, the most cpu consuming part of Jdempotent is getting a Redis connection so we don't need to worry performance related issues.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"examples/cpu-profiling.png\"\u003e\n\u003c/p\u003e\n\n# Docs\n\n[Jdempotent Medium Article](https://medium.com/trendyol-tech/an-idempotency-library-jdempotent-5cd2cd0b76ff) \u003cbr/\u003e\n[Jdempotent-core Javadoc](https://memojja.github.io/jdempotent-core/index.html) \u003cbr/\u003e\n[Jdempotent-spring-boot-redis-starter Javadoc](https://memojja.github.io/jdempotent-spring-boot-redis-starter/index.html)\n\n## Support\n\n[memojja's twitter](https://twitter.com/memojja) \u003cbr/\u003e\n\n## Licence\n\n[MIT Licence](https://opensource.org/licenses/MIT) \u003cbr/\u003e\n\n## Contributing\n\n1. Fork it ( https://github.com/Trendyol/Jdempotent/fork )\n2. Create your feature branch (git checkout -b my-new-feature)\n3. Commit your changes (git commit -am 'Add some feature')\n4. Push to the branch (git push origin my-new-feature)\n5. Create a new Pull Request\n\n## Contributors\n\n- [memojja](https://github.com/memojja) Mehmet ARI - creator, maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrendyol%2Fjdempotent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrendyol%2Fjdempotent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrendyol%2Fjdempotent/lists"}