{"action":"created","comment":{"url":"https://api.github.com/repos/iyzico/ozonosfer/pulls/comments/223225774","pull_request_review_id":162302408,"id":223225774,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyMzIyNTc3NA==","diff_hunk":"@@ -0,0 +1,103 @@\n+package com.iyzico.ozonosfer.infrastructure.service;\n+\n+import com.google.common.collect.Iterables;\n+import com.iyzico.ozonosfer.domain.exception.RateLimitedException;\n+import com.iyzico.ozonosfer.domain.model.RateLimitRequest;\n+import com.iyzico.ozonosfer.domain.model.RateLimitWindowSize;\n+import com.iyzico.ozonosfer.domain.service.RateLimiterService;\n+import org.jooq.lambda.tuple.Tuple;\n+import org.jooq.lambda.tuple.Tuple3;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\n+import org.springframework.data.redis.core.RedisOperations;\n+import org.springframework.data.redis.core.RedisTemplate;\n+import org.springframework.data.redis.core.SessionCallback;\n+import org.springframework.stereotype.Service;\n+\n+import java.time.LocalTime;\n+import java.util.List;\n+import java.util.Optional;\n+import java.util.concurrent.TimeUnit;\n+\n+/**\n+ * Basic redis rate limiter service implemented via https://redislabs.com/redis-best-practices/basic-rate-limiting/\n+ */\n+\n+@Service\n+@ConditionalOnProperty(prefix = \"ozonosfer.implementation\", name = \"redis\", matchIfMissing = true)\n+public class RedisBasicRateLimiterService implements RateLimiterService {\n+\n+    private Logger logger = LoggerFactory.getLogger(RedisBasicRateLimiterService.class);\n+\n+    private static final String DELIMITER = \":\";\n+    private static final String KEY_PREFIX_SECOND = \"ozon:s:\";\n+    private static final String KEY_PREFIX_MINUTE = \"ozon:m:\";\n+    private static final String KEY_PREFIX_HOUR = \"ozon:h:\";\n+    private static final double DELTA = 1.0;\n+\n+    private RedisTemplate<String, String> redisTemplate;\n+\n+    public RedisBasicRateLimiterService(RedisTemplate<String, String> redisTemplate) {\n+        this.redisTemplate = redisTemplate;\n+    }\n+\n+    @Override\n+    public void rateLimit(RateLimitRequest request) {\n+        Long count = retrieve(request);\n+        if (rateLimitExceeded(request.getLimit(), count)) {\n+            throw new RateLimitedException(request);\n+        } else {\n+            increment(request);\n+        }\n+    }\n+\n+    private boolean rateLimitExceeded(Long limit, Long count) {\n+        return count != null && count >= limit;","path":"ozonosfer-spring/src/main/java/com/iyzico/ozonosfer/infrastructure/service/RedisBasicRateLimiterService.java","position":56,"original_position":56,"commit_id":"3abf85589e94f252636d4d2941b4ca641b44b532","original_commit_id":"b1cab123b5bab3376e47a1edd34f3349646005bb","user":{"login":"aonurozcan","id":7273908,"node_id":"MDQ6VXNlcjcyNzM5MDg=","avatar_url":"https://avatars1.githubusercontent.com/u/7273908?v=4","gravatar_id":"","url":"https://api.github.com/users/aonurozcan","html_url":"https://github.com/aonurozcan","followers_url":"https://api.github.com/users/aonurozcan/followers","following_url":"https://api.github.com/users/aonurozcan/following{/other_user}","gists_url":"https://api.github.com/users/aonurozcan/gists{/gist_id}","starred_url":"https://api.github.com/users/aonurozcan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aonurozcan/subscriptions","organizations_url":"https://api.github.com/users/aonurozcan/orgs","repos_url":"https://api.github.com/users/aonurozcan/repos","events_url":"https://api.github.com/users/aonurozcan/events{/privacy}","received_events_url":"https://api.github.com/users/aonurozcan/received_events","type":"User","site_admin":false},"body":"Count cannot be null anymore. We might consider removing null check.","created_at":"2018-10-07T19:53:42Z","updated_at":"2018-10-07T19:53:43Z","html_url":"https://github.com/iyzico/ozonosfer/pull/9#discussion_r223225774","pull_request_url":"https://api.github.com/repos/iyzico/ozonosfer/pulls/9","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/iyzico/ozonosfer/pulls/comments/223225774"},"html":{"href":"https://github.com/iyzico/ozonosfer/pull/9#discussion_r223225774"},"pull_request":{"href":"https://api.github.com/repos/iyzico/ozonosfer/pulls/9"}}},"pull_request":{"url":"https://api.github.com/repos/iyzico/ozonosfer/pulls/9","id":220960663,"node_id":"MDExOlB1bGxSZXF1ZXN0MjIwOTYwNjYz","html_url":"https://github.com/iyzico/ozonosfer/pull/9","diff_url":"https://github.com/iyzico/ozonosfer/pull/9.diff","patch_url":"https://github.com/iyzico/ozonosfer/pull/9.patch","issue_url":"https://api.github.com/repos/iyzico/ozonosfer/issues/9","number":9,"state":"open","locked":false,"title":"Redis rate limiter service implemented","user":{"login":"yyenigun","id":105900,"node_id":"MDQ6VXNlcjEwNTkwMA==","avatar_url":"https://avatars2.githubusercontent.com/u/105900?v=4","gravatar_id":"","url":"https://api.github.com/users/yyenigun","html_url":"https://github.com/yyenigun","followers_url":"https://api.github.com/users/yyenigun/followers","following_url":"https://api.github.com/users/yyenigun/following{/other_user}","gists_url":"https://api.github.com/users/yyenigun/gists{/gist_id}","starred_url":"https://api.github.com/users/yyenigun/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yyenigun/subscriptions","organizations_url":"https://api.github.com/users/yyenigun/orgs","repos_url":"https://api.github.com/users/yyenigun/repos","events_url":"https://api.github.com/users/yyenigun/events{/privacy}","received_events_url":"https://api.github.com/users/yyenigun/received_events","type":"User","site_admin":false},"body":"Basic redis rate limiter service implemented via https://redislabs.com/redis-best-practices/basic-rate-limiting/ ","created_at":"2018-10-07T17:15:05Z","updated_at":"2018-10-07T19:53:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4ffd02b23d11e0ffd50e1bcfef5cf8277364dd82","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/iyzico/ozonosfer/pulls/9/commits","review_comments_url":"https://api.github.com/repos/iyzico/ozonosfer/pulls/9/comments","review_comment_url":"https://api.github.com/repos/iyzico/ozonosfer/pulls/comments{/number}","comments_url":"https://api.github.com/repos/iyzico/ozonosfer/issues/9/comments","statuses_url":"https://api.github.com/repos/iyzico/ozonosfer/statuses/3abf85589e94f252636d4d2941b4ca641b44b532","head":{"label":"yyenigun:redis-rate-limiter-service","ref":"redis-rate-limiter-service","sha":"3abf85589e94f252636d4d2941b4ca641b44b532","user":{"login":"yyenigun","id":105900,"node_id":"MDQ6VXNlcjEwNTkwMA==","avatar_url":"https://avatars2.githubusercontent.com/u/105900?v=4","gravatar_id":"","url":"https://api.github.com/users/yyenigun","html_url":"https://github.com/yyenigun","followers_url":"https://api.github.com/users/yyenigun/followers","following_url":"https://api.github.com/users/yyenigun/following{/other_user}","gists_url":"https://api.github.com/users/yyenigun/gists{/gist_id}","starred_url":"https://api.github.com/users/yyenigun/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yyenigun/subscriptions","organizations_url":"https://api.github.com/users/yyenigun/orgs","repos_url":"https://api.github.com/users/yyenigun/repos","events_url":"https://api.github.com/users/yyenigun/events{/privacy}","received_events_url":"https://api.github.com/users/yyenigun/received_events","type":"User","site_admin":false},"repo":{"id":148428717,"node_id":"MDEwOlJlcG9zaXRvcnkxNDg0Mjg3MTc=","name":"ozonosfer","full_name":"yyenigun/ozonosfer","private":false,"owner":{"login":"yyenigun","id":105900,"node_id":"MDQ6VXNlcjEwNTkwMA==","avatar_url":"https://avatars2.githubusercontent.com/u/105900?v=4","gravatar_id":"","url":"https://api.github.com/users/yyenigun","html_url":"https://github.com/yyenigun","followers_url":"https://api.github.com/users/yyenigun/followers","following_url":"https://api.github.com/users/yyenigun/following{/other_user}","gists_url":"https://api.github.com/users/yyenigun/gists{/gist_id}","starred_url":"https://api.github.com/users/yyenigun/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yyenigun/subscriptions","organizations_url":"https://api.github.com/users/yyenigun/orgs","repos_url":"https://api.github.com/users/yyenigun/repos","events_url":"https://api.github.com/users/yyenigun/events{/privacy}","received_events_url":"https://api.github.com/users/yyenigun/received_events","type":"User","site_admin":false},"html_url":"https://github.com/yyenigun/ozonosfer","description":"Intelligent scalable rate limiter","fork":true,"url":"https://api.github.com/repos/yyenigun/ozonosfer","forks_url":"https://api.github.com/repos/yyenigun/ozonosfer/forks","keys_url":"https://api.github.com/repos/yyenigun/ozonosfer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/yyenigun/ozonosfer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/yyenigun/ozonosfer/teams","hooks_url":"https://api.github.com/repos/yyenigun/ozonosfer/hooks","issue_events_url":"https://api.github.com/repos/yyenigun/ozonosfer/issues/events{/number}","events_url":"https://api.github.com/repos/yyenigun/ozonosfer/events","assignees_url":"https://api.github.com/repos/yyenigun/ozonosfer/assignees{/user}","branches_url":"https://api.github.com/repos/yyenigun/ozonosfer/branches{/branch}","tags_url":"https://api.github.com/repos/yyenigun/ozonosfer/tags","blobs_url":"https://api.github.com/repos/yyenigun/ozonosfer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/yyenigun/ozonosfer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/yyenigun/ozonosfer/git/refs{/sha}","trees_url":"https://api.github.com/repos/yyenigun/ozonosfer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/yyenigun/ozonosfer/statuses/{sha}","languages_url":"https://api.github.com/repos/yyenigun/ozonosfer/languages","stargazers_url":"https://api.github.com/repos/yyenigun/ozonosfer/stargazers","contributors_url":"https://api.github.com/repos/yyenigun/ozonosfer/contributors","subscribers_url":"https://api.github.com/repos/yyenigun/ozonosfer/subscribers","subscription_url":"https://api.github.com/repos/yyenigun/ozonosfer/subscription","commits_url":"https://api.github.com/repos/yyenigun/ozonosfer/commits{/sha}","git_commits_url":"https://api.github.com/repos/yyenigun/ozonosfer/git/commits{/sha}","comments_url":"https://api.github.com/repos/yyenigun/ozonosfer/comments{/number}","issue_comment_url":"https://api.github.com/repos/yyenigun/ozonosfer/issues/comments{/number}","contents_url":"https://api.github.com/repos/yyenigun/ozonosfer/contents/{+path}","compare_url":"https://api.github.com/repos/yyenigun/ozonosfer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/yyenigun/ozonosfer/merges","archive_url":"https://api.github.com/repos/yyenigun/ozonosfer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/yyenigun/ozonosfer/downloads","issues_url":"https://api.github.com/repos/yyenigun/ozonosfer/issues{/number}","pulls_url":"https://api.github.com/repos/yyenigun/ozonosfer/pulls{/number}","milestones_url":"https://api.github.com/repos/yyenigun/ozonosfer/milestones{/number}","notifications_url":"https://api.github.com/repos/yyenigun/ozonosfer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/yyenigun/ozonosfer/labels{/name}","releases_url":"https://api.github.com/repos/yyenigun/ozonosfer/releases{/id}","deployments_url":"https://api.github.com/repos/yyenigun/ozonosfer/deployments","created_at":"2018-09-12T05:55:53Z","updated_at":"2018-09-12T05:55:55Z","pushed_at":"2018-10-07T19:53:20Z","git_url":"git://github.com/yyenigun/ozonosfer.git","ssh_url":"git@github.com:yyenigun/ozonosfer.git","clone_url":"https://github.com/yyenigun/ozonosfer.git","svn_url":"https://github.com/yyenigun/ozonosfer","homepage":null,"size":32,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"iyzico:master","ref":"master","sha":"38c94148302d260b74283d34d506ed12d754f48a","user":{"login":"iyzico","id":3815564,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM4MTU1NjQ=","avatar_url":"https://avatars3.githubusercontent.com/u/3815564?v=4","gravatar_id":"","url":"https://api.github.com/users/iyzico","html_url":"https://github.com/iyzico","followers_url":"https://api.github.com/users/iyzico/followers","following_url":"https://api.github.com/users/iyzico/following{/other_user}","gists_url":"https://api.github.com/users/iyzico/gists{/gist_id}","starred_url":"https://api.github.com/users/iyzico/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iyzico/subscriptions","organizations_url":"https://api.github.com/users/iyzico/orgs","repos_url":"https://api.github.com/users/iyzico/repos","events_url":"https://api.github.com/users/iyzico/events{/privacy}","received_events_url":"https://api.github.com/users/iyzico/received_events","type":"Organization","site_admin":false},"repo":{"id":148374250,"node_id":"MDEwOlJlcG9zaXRvcnkxNDgzNzQyNTA=","name":"ozonosfer","full_name":"iyzico/ozonosfer","private":false,"owner":{"login":"iyzico","id":3815564,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM4MTU1NjQ=","avatar_url":"https://avatars3.githubusercontent.com/u/3815564?v=4","gravatar_id":"","url":"https://api.github.com/users/iyzico","html_url":"https://github.com/iyzico","followers_url":"https://api.github.com/users/iyzico/followers","following_url":"https://api.github.com/users/iyzico/following{/other_user}","gists_url":"https://api.github.com/users/iyzico/gists{/gist_id}","starred_url":"https://api.github.com/users/iyzico/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iyzico/subscriptions","organizations_url":"https://api.github.com/users/iyzico/orgs","repos_url":"https://api.github.com/users/iyzico/repos","events_url":"https://api.github.com/users/iyzico/events{/privacy}","received_events_url":"https://api.github.com/users/iyzico/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/iyzico/ozonosfer","description":"Intelligent scalable rate limiter","fork":false,"url":"https://api.github.com/repos/iyzico/ozonosfer","forks_url":"https://api.github.com/repos/iyzico/ozonosfer/forks","keys_url":"https://api.github.com/repos/iyzico/ozonosfer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/iyzico/ozonosfer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/iyzico/ozonosfer/teams","hooks_url":"https://api.github.com/repos/iyzico/ozonosfer/hooks","issue_events_url":"https://api.github.com/repos/iyzico/ozonosfer/issues/events{/number}","events_url":"https://api.github.com/repos/iyzico/ozonosfer/events","assignees_url":"https://api.github.com/repos/iyzico/ozonosfer/assignees{/user}","branches_url":"https://api.github.com/repos/iyzico/ozonosfer/branches{/branch}","tags_url":"https://api.github.com/repos/iyzico/ozonosfer/tags","blobs_url":"https://api.github.com/repos/iyzico/ozonosfer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/iyzico/ozonosfer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/iyzico/ozonosfer/git/refs{/sha}","trees_url":"https://api.github.com/repos/iyzico/ozonosfer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/iyzico/ozonosfer/statuses/{sha}","languages_url":"https://api.github.com/repos/iyzico/ozonosfer/languages","stargazers_url":"https://api.github.com/repos/iyzico/ozonosfer/stargazers","contributors_url":"https://api.github.com/repos/iyzico/ozonosfer/contributors","subscribers_url":"https://api.github.com/repos/iyzico/ozonosfer/subscribers","subscription_url":"https://api.github.com/repos/iyzico/ozonosfer/subscription","commits_url":"https://api.github.com/repos/iyzico/ozonosfer/commits{/sha}","git_commits_url":"https://api.github.com/repos/iyzico/ozonosfer/git/commits{/sha}","comments_url":"https://api.github.com/repos/iyzico/ozonosfer/comments{/number}","issue_comment_url":"https://api.github.com/repos/iyzico/ozonosfer/issues/comments{/number}","contents_url":"https://api.github.com/repos/iyzico/ozonosfer/contents/{+path}","compare_url":"https://api.github.com/repos/iyzico/ozonosfer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/iyzico/ozonosfer/merges","archive_url":"https://api.github.com/repos/iyzico/ozonosfer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/iyzico/ozonosfer/downloads","issues_url":"https://api.github.com/repos/iyzico/ozonosfer/issues{/number}","pulls_url":"https://api.github.com/repos/iyzico/ozonosfer/pulls{/number}","milestones_url":"https://api.github.com/repos/iyzico/ozonosfer/milestones{/number}","notifications_url":"https://api.github.com/repos/iyzico/ozonosfer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/iyzico/ozonosfer/labels{/name}","releases_url":"https://api.github.com/repos/iyzico/ozonosfer/releases{/id}","deployments_url":"https://api.github.com/repos/iyzico/ozonosfer/deployments","created_at":"2018-09-11T20:10:49Z","updated_at":"2018-10-07T12:08:05Z","pushed_at":"2018-10-07T19:53:21Z","git_url":"git://github.com/iyzico/ozonosfer.git","ssh_url":"git@github.com:iyzico/ozonosfer.git","clone_url":"https://github.com/iyzico/ozonosfer.git","svn_url":"https://github.com/iyzico/ozonosfer","homepage":null,"size":12,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"archived":false,"open_issues_count":4,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":3,"open_issues":4,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/iyzico/ozonosfer/pulls/9"},"html":{"href":"https://github.com/iyzico/ozonosfer/pull/9"},"issue":{"href":"https://api.github.com/repos/iyzico/ozonosfer/issues/9"},"comments":{"href":"https://api.github.com/repos/iyzico/ozonosfer/issues/9/comments"},"review_comments":{"href":"https://api.github.com/repos/iyzico/ozonosfer/pulls/9/comments"},"review_comment":{"href":"https://api.github.com/repos/iyzico/ozonosfer/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/iyzico/ozonosfer/pulls/9/commits"},"statuses":{"href":"https://api.github.com/repos/iyzico/ozonosfer/statuses/3abf85589e94f252636d4d2941b4ca641b44b532"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"aonurozcan"}}