{"action":"created","comment":{"url":"https://api.github.com/repos/gmcquillan/django-brake/pulls/comments/48632995","id":48632995,"diff_hunk":"@@ -51,12 +52,13 @@ def _keys(self, func_name, request, ip=True, field=None, period=None):\n \n     def count(self, func_name, request, ip=True, field=None, period=60):\n         \"\"\"Increment counters for all relevant cache_keys given a request.\"\"\"\n-        counters = dict((key, 1) for key in self._keys(\n+        counters = dict((key, (1, time.time() + period)) for key in self._keys(\n             func_name, request, ip, field, period))\n         counters.update(cache.get_many(counters.keys()))\n-        for key in counters:\n-            counters[key] += 1\n-        cache.set_many(counters, timeout=period)\n+        for key, value in counters.items():\n+            count, expiration = value\n+            count += 1\n+            cache.set(key, (count, expiration), timeout=expiration - time.time())","path":"brake/backends/cachebe.py","position":20,"original_position":20,"commit_id":"b5aacd9924bd5cbda8d069828f615ff1bb719aef","original_commit_id":"b5aacd9924bd5cbda8d069828f615ff1bb719aef","user":{"login":"gmcquillan","id":313116,"avatar_url":"https://avatars.githubusercontent.com/u/313116?v=3","gravatar_id":"","url":"https://api.github.com/users/gmcquillan","html_url":"https://github.com/gmcquillan","followers_url":"https://api.github.com/users/gmcquillan/followers","following_url":"https://api.github.com/users/gmcquillan/following{/other_user}","gists_url":"https://api.github.com/users/gmcquillan/gists{/gist_id}","starred_url":"https://api.github.com/users/gmcquillan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gmcquillan/subscriptions","organizations_url":"https://api.github.com/users/gmcquillan/orgs","repos_url":"https://api.github.com/users/gmcquillan/repos","events_url":"https://api.github.com/users/gmcquillan/events{/privacy}","received_events_url":"https://api.github.com/users/gmcquillan/received_events","type":"User","site_admin":false},"body":"Okay, this is pretty clever. So when you pass a tuple into the value for ```cache.set``` how does it serialize, pickle?\r\n\r\nAlso, am I missing something, or is nothing reading the expiration out of the memcached value?","created_at":"2015-12-30T21:32:32Z","updated_at":"2015-12-30T21:32:32Z","html_url":"https://github.com/gmcquillan/django-brake/pull/21#discussion_r48632995","pull_request_url":"https://api.github.com/repos/gmcquillan/django-brake/pulls/21","_links":{"self":{"href":"https://api.github.com/repos/gmcquillan/django-brake/pulls/comments/48632995"},"html":{"href":"https://github.com/gmcquillan/django-brake/pull/21#discussion_r48632995"},"pull_request":{"href":"https://api.github.com/repos/gmcquillan/django-brake/pulls/21"}}},"pull_request":{"url":"https://api.github.com/repos/gmcquillan/django-brake/pulls/21","id":54827340,"html_url":"https://github.com/gmcquillan/django-brake/pull/21","diff_url":"https://github.com/gmcquillan/django-brake/pull/21.diff","patch_url":"https://github.com/gmcquillan/django-brake/pull/21.patch","issue_url":"https://api.github.com/repos/gmcquillan/django-brake/issues/21","number":21,"state":"open","locked":false,"title":"Improve rate-limiting windowing for the default cache backend.","user":{"login":"skorokithakis","id":23648,"avatar_url":"https://avatars.githubusercontent.com/u/23648?v=3","gravatar_id":"","url":"https://api.github.com/users/skorokithakis","html_url":"https://github.com/skorokithakis","followers_url":"https://api.github.com/users/skorokithakis/followers","following_url":"https://api.github.com/users/skorokithakis/following{/other_user}","gists_url":"https://api.github.com/users/skorokithakis/gists{/gist_id}","starred_url":"https://api.github.com/users/skorokithakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/skorokithakis/subscriptions","organizations_url":"https://api.github.com/users/skorokithakis/orgs","repos_url":"https://api.github.com/users/skorokithakis/repos","events_url":"https://api.github.com/users/skorokithakis/events{/privacy}","received_events_url":"https://api.github.com/users/skorokithakis/received_events","type":"User","site_admin":false},"body":"This is related to #20. Instead of renewing the rate limit every request, this PR resets the limits every `period` seconds.\r\n\r\nThis means that:\r\n\r\n* Originally, if you set a limit of 10/minute and performed one request every 30 seconds, you would get rate-limited after 11 requests, since the counter would never reset.\r\n* After this change, the counter resets every minute, so performing one request every 30 seconds will never get you rate-limited.\r\n\r\nThere is an issue in this PR that will require the cache to be cleared when upgrading, due to the changing data format in the cache key. I can check the data type and upgrade backwards-compatibly, if needed.","created_at":"2015-12-30T20:30:07Z","updated_at":"2015-12-30T21:32:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f7793d96937b2ce26d66822605a28c2e22c180bc","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/gmcquillan/django-brake/pulls/21/commits","review_comments_url":"https://api.github.com/repos/gmcquillan/django-brake/pulls/21/comments","review_comment_url":"https://api.github.com/repos/gmcquillan/django-brake/pulls/comments{/number}","comments_url":"https://api.github.com/repos/gmcquillan/django-brake/issues/21/comments","statuses_url":"https://api.github.com/repos/gmcquillan/django-brake/statuses/b5aacd9924bd5cbda8d069828f615ff1bb719aef","head":{"label":"skorokithakis:master","ref":"master","sha":"b5aacd9924bd5cbda8d069828f615ff1bb719aef","user":{"login":"skorokithakis","id":23648,"avatar_url":"https://avatars.githubusercontent.com/u/23648?v=3","gravatar_id":"","url":"https://api.github.com/users/skorokithakis","html_url":"https://github.com/skorokithakis","followers_url":"https://api.github.com/users/skorokithakis/followers","following_url":"https://api.github.com/users/skorokithakis/following{/other_user}","gists_url":"https://api.github.com/users/skorokithakis/gists{/gist_id}","starred_url":"https://api.github.com/users/skorokithakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/skorokithakis/subscriptions","organizations_url":"https://api.github.com/users/skorokithakis/orgs","repos_url":"https://api.github.com/users/skorokithakis/repos","events_url":"https://api.github.com/users/skorokithakis/events{/privacy}","received_events_url":"https://api.github.com/users/skorokithakis/received_events","type":"User","site_admin":false},"repo":{"id":48818176,"name":"django-brake","full_name":"skorokithakis/django-brake","owner":{"login":"skorokithakis","id":23648,"avatar_url":"https://avatars.githubusercontent.com/u/23648?v=3","gravatar_id":"","url":"https://api.github.com/users/skorokithakis","html_url":"https://github.com/skorokithakis","followers_url":"https://api.github.com/users/skorokithakis/followers","following_url":"https://api.github.com/users/skorokithakis/following{/other_user}","gists_url":"https://api.github.com/users/skorokithakis/gists{/gist_id}","starred_url":"https://api.github.com/users/skorokithakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/skorokithakis/subscriptions","organizations_url":"https://api.github.com/users/skorokithakis/orgs","repos_url":"https://api.github.com/users/skorokithakis/repos","events_url":"https://api.github.com/users/skorokithakis/events{/privacy}","received_events_url":"https://api.github.com/users/skorokithakis/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/skorokithakis/django-brake","description":"Django Brake - a versatile ratelimiting app for Django.","fork":true,"url":"https://api.github.com/repos/skorokithakis/django-brake","forks_url":"https://api.github.com/repos/skorokithakis/django-brake/forks","keys_url":"https://api.github.com/repos/skorokithakis/django-brake/keys{/key_id}","collaborators_url":"https://api.github.com/repos/skorokithakis/django-brake/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/skorokithakis/django-brake/teams","hooks_url":"https://api.github.com/repos/skorokithakis/django-brake/hooks","issue_events_url":"https://api.github.com/repos/skorokithakis/django-brake/issues/events{/number}","events_url":"https://api.github.com/repos/skorokithakis/django-brake/events","assignees_url":"https://api.github.com/repos/skorokithakis/django-brake/assignees{/user}","branches_url":"https://api.github.com/repos/skorokithakis/django-brake/branches{/branch}","tags_url":"https://api.github.com/repos/skorokithakis/django-brake/tags","blobs_url":"https://api.github.com/repos/skorokithakis/django-brake/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/skorokithakis/django-brake/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/skorokithakis/django-brake/git/refs{/sha}","trees_url":"https://api.github.com/repos/skorokithakis/django-brake/git/trees{/sha}","statuses_url":"https://api.github.com/repos/skorokithakis/django-brake/statuses/{sha}","languages_url":"https://api.github.com/repos/skorokithakis/django-brake/languages","stargazers_url":"https://api.github.com/repos/skorokithakis/django-brake/stargazers","contributors_url":"https://api.github.com/repos/skorokithakis/django-brake/contributors","subscribers_url":"https://api.github.com/repos/skorokithakis/django-brake/subscribers","subscription_url":"https://api.github.com/repos/skorokithakis/django-brake/subscription","commits_url":"https://api.github.com/repos/skorokithakis/django-brake/commits{/sha}","git_commits_url":"https://api.github.com/repos/skorokithakis/django-brake/git/commits{/sha}","comments_url":"https://api.github.com/repos/skorokithakis/django-brake/comments{/number}","issue_comment_url":"https://api.github.com/repos/skorokithakis/django-brake/issues/comments{/number}","contents_url":"https://api.github.com/repos/skorokithakis/django-brake/contents/{+path}","compare_url":"https://api.github.com/repos/skorokithakis/django-brake/compare/{base}...{head}","merges_url":"https://api.github.com/repos/skorokithakis/django-brake/merges","archive_url":"https://api.github.com/repos/skorokithakis/django-brake/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/skorokithakis/django-brake/downloads","issues_url":"https://api.github.com/repos/skorokithakis/django-brake/issues{/number}","pulls_url":"https://api.github.com/repos/skorokithakis/django-brake/pulls{/number}","milestones_url":"https://api.github.com/repos/skorokithakis/django-brake/milestones{/number}","notifications_url":"https://api.github.com/repos/skorokithakis/django-brake/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/skorokithakis/django-brake/labels{/name}","releases_url":"https://api.github.com/repos/skorokithakis/django-brake/releases{/id}","created_at":"2015-12-30T20:25:27Z","updated_at":"2015-12-30T20:25:28Z","pushed_at":"2015-12-30T20:27:31Z","git_url":"git://github.com/skorokithakis/django-brake.git","ssh_url":"git@github.com:skorokithakis/django-brake.git","clone_url":"https://github.com/skorokithakis/django-brake.git","svn_url":"https://github.com/skorokithakis/django-brake","homepage":null,"size":55,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"gmcquillan:master","ref":"master","sha":"ed752d5219d1ad05760f40a647ec34f210cd0961","user":{"login":"gmcquillan","id":313116,"avatar_url":"https://avatars.githubusercontent.com/u/313116?v=3","gravatar_id":"","url":"https://api.github.com/users/gmcquillan","html_url":"https://github.com/gmcquillan","followers_url":"https://api.github.com/users/gmcquillan/followers","following_url":"https://api.github.com/users/gmcquillan/following{/other_user}","gists_url":"https://api.github.com/users/gmcquillan/gists{/gist_id}","starred_url":"https://api.github.com/users/gmcquillan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gmcquillan/subscriptions","organizations_url":"https://api.github.com/users/gmcquillan/orgs","repos_url":"https://api.github.com/users/gmcquillan/repos","events_url":"https://api.github.com/users/gmcquillan/events{/privacy}","received_events_url":"https://api.github.com/users/gmcquillan/received_events","type":"User","site_admin":false},"repo":{"id":6663686,"name":"django-brake","full_name":"gmcquillan/django-brake","owner":{"login":"gmcquillan","id":313116,"avatar_url":"https://avatars.githubusercontent.com/u/313116?v=3","gravatar_id":"","url":"https://api.github.com/users/gmcquillan","html_url":"https://github.com/gmcquillan","followers_url":"https://api.github.com/users/gmcquillan/followers","following_url":"https://api.github.com/users/gmcquillan/following{/other_user}","gists_url":"https://api.github.com/users/gmcquillan/gists{/gist_id}","starred_url":"https://api.github.com/users/gmcquillan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gmcquillan/subscriptions","organizations_url":"https://api.github.com/users/gmcquillan/orgs","repos_url":"https://api.github.com/users/gmcquillan/repos","events_url":"https://api.github.com/users/gmcquillan/events{/privacy}","received_events_url":"https://api.github.com/users/gmcquillan/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/gmcquillan/django-brake","description":"Django Brake - a versatile ratelimiting app for Django.","fork":false,"url":"https://api.github.com/repos/gmcquillan/django-brake","forks_url":"https://api.github.com/repos/gmcquillan/django-brake/forks","keys_url":"https://api.github.com/repos/gmcquillan/django-brake/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gmcquillan/django-brake/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gmcquillan/django-brake/teams","hooks_url":"https://api.github.com/repos/gmcquillan/django-brake/hooks","issue_events_url":"https://api.github.com/repos/gmcquillan/django-brake/issues/events{/number}","events_url":"https://api.github.com/repos/gmcquillan/django-brake/events","assignees_url":"https://api.github.com/repos/gmcquillan/django-brake/assignees{/user}","branches_url":"https://api.github.com/repos/gmcquillan/django-brake/branches{/branch}","tags_url":"https://api.github.com/repos/gmcquillan/django-brake/tags","blobs_url":"https://api.github.com/repos/gmcquillan/django-brake/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gmcquillan/django-brake/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gmcquillan/django-brake/git/refs{/sha}","trees_url":"https://api.github.com/repos/gmcquillan/django-brake/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gmcquillan/django-brake/statuses/{sha}","languages_url":"https://api.github.com/repos/gmcquillan/django-brake/languages","stargazers_url":"https://api.github.com/repos/gmcquillan/django-brake/stargazers","contributors_url":"https://api.github.com/repos/gmcquillan/django-brake/contributors","subscribers_url":"https://api.github.com/repos/gmcquillan/django-brake/subscribers","subscription_url":"https://api.github.com/repos/gmcquillan/django-brake/subscription","commits_url":"https://api.github.com/repos/gmcquillan/django-brake/commits{/sha}","git_commits_url":"https://api.github.com/repos/gmcquillan/django-brake/git/commits{/sha}","comments_url":"https://api.github.com/repos/gmcquillan/django-brake/comments{/number}","issue_comment_url":"https://api.github.com/repos/gmcquillan/django-brake/issues/comments{/number}","contents_url":"https://api.github.com/repos/gmcquillan/django-brake/contents/{+path}","compare_url":"https://api.github.com/repos/gmcquillan/django-brake/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gmcquillan/django-brake/merges","archive_url":"https://api.github.com/repos/gmcquillan/django-brake/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gmcquillan/django-brake/downloads","issues_url":"https://api.github.com/repos/gmcquillan/django-brake/issues{/number}","pulls_url":"https://api.github.com/repos/gmcquillan/django-brake/pulls{/number}","milestones_url":"https://api.github.com/repos/gmcquillan/django-brake/milestones{/number}","notifications_url":"https://api.github.com/repos/gmcquillan/django-brake/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gmcquillan/django-brake/labels{/name}","releases_url":"https://api.github.com/repos/gmcquillan/django-brake/releases{/id}","created_at":"2012-11-13T01:29:33Z","updated_at":"2015-12-30T20:30:18Z","pushed_at":"2015-12-30T20:30:08Z","git_url":"git://github.com/gmcquillan/django-brake.git","ssh_url":"git@github.com:gmcquillan/django-brake.git","clone_url":"https://github.com/gmcquillan/django-brake.git","svn_url":"https://github.com/gmcquillan/django-brake","homepage":null,"size":332,"stargazers_count":83,"watchers_count":83,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":13,"mirror_url":null,"open_issues_count":5,"forks":13,"open_issues":5,"watchers":83,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/gmcquillan/django-brake/pulls/21"},"html":{"href":"https://github.com/gmcquillan/django-brake/pull/21"},"issue":{"href":"https://api.github.com/repos/gmcquillan/django-brake/issues/21"},"comments":{"href":"https://api.github.com/repos/gmcquillan/django-brake/issues/21/comments"},"review_comments":{"href":"https://api.github.com/repos/gmcquillan/django-brake/pulls/21/comments"},"review_comment":{"href":"https://api.github.com/repos/gmcquillan/django-brake/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/gmcquillan/django-brake/pulls/21/commits"},"statuses":{"href":"https://api.github.com/repos/gmcquillan/django-brake/statuses/b5aacd9924bd5cbda8d069828f615ff1bb719aef"}}}}