{"payload":{"feedbackUrl":"https://github.com/orgs/community/discussions/53140","repo":{"id":712096860,"defaultBranch":"main","name":"pecorino","ownerLogin":"cheddar-me","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2023-10-30T19:32:14.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/71437242?v=4","public":true,"private":false,"isOrgOwned":true},"refInfo":{"name":"","listCacheKey":"v0:1716198114.0","currentOid":""},"activityList":{"items":[{"before":"96d0dcc579812aa2d672d5ddb7ede61aa6fa0a39","after":"36dc3cf0f971c3fcbfa302d8704b72e0601f729a","ref":"refs/heads/main","pushedAt":"2024-05-20T09:36:56.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Remove UUID generation from SQLite functions","shortMessageHtmlLink":"Remove UUID generation from SQLite functions"}},{"before":"8b25ba5d175ce441a27af1991299c172e2658a41","after":"96d0dcc579812aa2d672d5ddb7ede61aa6fa0a39","ref":"refs/heads/main","pushedAt":"2024-05-20T09:10:01.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"SQLite does not have a native UUID type","shortMessageHtmlLink":"SQLite does not have a native UUID type"}},{"before":"65a65aff1c0cca452b54720088bf27c417b36793","after":"8b25ba5d175ce441a27af1991299c172e2658a41","ref":"refs/heads/main","pushedAt":"2024-05-14T10:07:59.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Remove mention of GoodJob (#21)\n\nGoodJob is a great gem, but doesn't have much to do with this gem.","shortMessageHtmlLink":"Remove mention of GoodJob (#21)"}},{"before":null,"after":"64977346ef97ae96dca9a2e5b325a247968e4f3e","ref":"refs/heads/not-a-good-job","pushedAt":"2024-05-13T16:00:28.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"skatkov","name":"Stanislav (Stas) Katkov","path":"/skatkov","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/544377?s=80&v=4"},"commit":{"message":"Remove mention of GoodJob","shortMessageHtmlLink":"Remove mention of GoodJob"}},{"before":"35fd837ce14f789eb82fd9858250ff5ea070aecb","after":"65a65aff1c0cca452b54720088bf27c417b36793","ref":"refs/heads/main","pushedAt":"2024-04-06T11:02:17.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Extract Adapters, add Redis adapter (#18)\n\nThis also adds a Redis adapter and a Memory adapter. The Redis adapter is useful since it can be a continuation of Prorate in a way - but with conditional fillup added in.\r\n\r\nThe memory store is useful in a different way - it can be used as a reference implementation to test other adapters against. Also make the adapter configurable on the `Pecorino` module.","shortMessageHtmlLink":"Extract Adapters, add Redis adapter (#18)"}},{"before":"5a4bb2b6956aa81f6516f62297ae4d6e7d700a51","after":"047c9f005188f85b28058b550dd83e9750b4a08e","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-03-20T11:38:17.000Z","pushType":"push","commitsCount":4,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Improve memory store cleanup","shortMessageHtmlLink":"Improve memory store cleanup"}},{"before":"99ab0f8a1a09a871f4d7a65327cb26efcfeb921c","after":"5a4bb2b6956aa81f6516f62297ae4d6e7d700a51","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-03-12T22:00:23.000Z","pushType":"force_push","commitsCount":0,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Bump version and changelog","shortMessageHtmlLink":"Bump version and changelog"}},{"before":"f900938a42e0c498698171f634653b79a8648d55","after":"35fd837ce14f789eb82fd9858250ff5ea070aecb","ref":"refs/heads/main","pushedAt":"2024-03-12T14:28:51.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Add naked Block\n\nfor blocking for an arbitrary timespan","shortMessageHtmlLink":"Add naked Block"}},{"before":"f4af87f5234f325c32533f290a4ab788456f5ea0","after":"f900938a42e0c498698171f634653b79a8648d55","ref":"refs/heads/main","pushedAt":"2024-03-02T17:42:27.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Note the transaction caveat","shortMessageHtmlLink":"Note the transaction caveat"}},{"before":"585576c8ddbf1e652c1b0475dfec681fdc3a7af5","after":"99ab0f8a1a09a871f4d7a65327cb26efcfeb921c","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-28T19:32:10.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Zap DatabaseAdapter\n\nRule of 3","shortMessageHtmlLink":"Zap DatabaseAdapter"}},{"before":"0ad6416f9f92de3bd26b9bba8d3cf382e60fad15","after":"585576c8ddbf1e652c1b0475dfec681fdc3a7af5","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-28T19:28:05.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Document Redis is available now","shortMessageHtmlLink":"Document Redis is available now"}},{"before":"04af47e66367a9153176a8ad917604a86cbb6d6e","after":"0ad6416f9f92de3bd26b9bba8d3cf382e60fad15","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-28T19:26:38.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Just on push is sufficient","shortMessageHtmlLink":"Just on push is sufficient"}},{"before":"a843f6a1733fd3e14b6649fa5d5ccebf5841c7ca","after":"04af47e66367a9153176a8ad917604a86cbb6d6e","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-28T19:25:57.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Remove unneeded lint step","shortMessageHtmlLink":"Remove unneeded lint step"}},{"before":"296f70a977f85a22495be69e8014d275b6517300","after":"a843f6a1733fd3e14b6649fa5d5ccebf5841c7ca","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-28T19:25:23.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Reformat","shortMessageHtmlLink":"Reformat"}},{"before":"90610994a0dace1a2d250beb9430f10a8bb1efcb","after":"296f70a977f85a22495be69e8014d275b6517300","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-28T19:22:38.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Add Redis in CI","shortMessageHtmlLink":"Add Redis in CI"}},{"before":"d56308a5c36f9f63d5fb6cd78fcfe9e6cce4651d","after":"90610994a0dace1a2d250beb9430f10a8bb1efcb","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-27T12:07:26.000Z","pushType":"push","commitsCount":2,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Structure tests a bit better still","shortMessageHtmlLink":"Structure tests a bit better still"}},{"before":"821503a9c8ecdf493afc53440a5d47eb338a037f","after":"d56308a5c36f9f63d5fb6cd78fcfe9e6cce4651d","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-26T20:37:03.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"A bit more Volkswagening","shortMessageHtmlLink":"A bit more Volkswagening"}},{"before":"30c7c3fe5c0312d5e68a1126a2f9ad114ad7a326","after":"821503a9c8ecdf493afc53440a5d47eb338a037f","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-26T17:17:18.000Z","pushType":"push","commitsCount":3,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"That mostly works","shortMessageHtmlLink":"That mostly works"}},{"before":null,"after":"30c7c3fe5c0312d5e68a1126a2f9ad114ad7a326","ref":"refs/heads/extract-adapters-better","pushedAt":"2024-02-26T09:12:27.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Script comment","shortMessageHtmlLink":"Script comment"}},{"before":"91a28dabc1d15141f222918f5735746fd674e4f5","after":"f4af87f5234f325c32533f290a4ab788456f5ea0","ref":"refs/heads/main","pushedAt":"2024-02-25T11:11:56.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Add more links about the algorithms","shortMessageHtmlLink":"Add more links about the algorithms"}},{"before":"b1bf06c3dfc3d9b3b56e282106315255a815cbc2","after":"91a28dabc1d15141f222918f5735746fd674e4f5","ref":"refs/heads/main","pushedAt":"2024-02-11T18:26:30.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Bump version","shortMessageHtmlLink":"Bump version"}},{"before":"35e42def16e06b131477ab732fe7ed9ac4322eb8","after":"b1bf06c3dfc3d9b3b56e282106315255a815cbc2","ref":"refs/heads/main","pushedAt":"2024-02-11T18:24:55.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Add throttle caching (#17)\n\nThe cached throttles can be used when you want to lift your throttle blocks into a higher-level cache. If you are dealing with clients which are hammering on your throttles a lot, it is useful to have a process-local cache of the timestamp when the blocks that are set are going to expire. If you are running, say, 10 web app containers - and someone is hammering at an endpoint which starts blocking - you don't really need to query your DB for every request. The first request indicated as \"blocked\" by Pecorino can write a cache entry into a shared in-memory table, and all subsequent calls to the same process can reuse that `blocked_until` value to quickly refuse the request","shortMessageHtmlLink":"Add throttle caching (#17)"}},{"before":"512bd66a9e69143dc2dcf68b5d86a81fe8fc98c3","after":"d0bf073d6661a7401d202209ca20c9c7630146f1","ref":"refs/heads/add-cached-throttle","pushedAt":"2024-02-11T18:21:16.000Z","pushType":"push","commitsCount":3,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Straighten a few things out","shortMessageHtmlLink":"Straighten a few things out"}},{"before":null,"after":"512bd66a9e69143dc2dcf68b5d86a81fe8fc98c3","ref":"refs/heads/add-cached-throttle","pushedAt":"2024-02-11T17:59:00.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Add throttle caching\n\nThis can be used when a block is in effect and a faster, memory-based cache store can be used","shortMessageHtmlLink":"Add throttle caching"}},{"before":"4ae0f7f95a227f731bf41bd95de000121148de83","after":"35e42def16e06b131477ab732fe7ed9ac4322eb8","ref":"refs/heads/main","pushedAt":"2024-02-11T17:13:16.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Add `Throttle#throttled` (#15)\n\nsince this is a pattern which we turned out to use frequently","shortMessageHtmlLink":"Add Throttle#throttled (#15)"}},{"before":"6d890b048767774a19b01fe8d161222e1aab137f","after":"9d540355c55b272b7cf33f224f15cf079d83619f","ref":"refs/heads/add-throttled-method","pushedAt":"2024-02-11T17:10:06.000Z","pushType":"force_push","commitsCount":0,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Add `Throttle#throttled`\n\nsince this is a pattern which we turned out to use frequently","shortMessageHtmlLink":"Add Throttle#throttled"}},{"before":"ca4baa9a67ca36d37529771e7284b99ce12e119f","after":"4ae0f7f95a227f731bf41bd95de000121148de83","ref":"refs/heads/main","pushedAt":"2024-02-11T17:08:51.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Prepare Pecorino::Throttle for caching support (#16)\n\nWhen a resource is getting hammered, it can be nice to save the throttle blocked state in a faster/edge datastore, like an ActiveSupport MemoryStore, or in Rails cache. To do that, we need to let the Throttle exception communicate the duration of the block in an easier manner.\r\n\r\nState#retry_after is getting removed since it was raising a NoMethodError when accessed for a non-blocked Throttle.\r\n\r\n- **BREAKING CHANGE** Remove `Throttle::State#retry_after`, because there is no reasonable value for that member if the throttle is not in the \"blocked\" state\r\n- Allow accessing `Throttle::State` from the `Throttled` exception so that the blocked throttle state can be cached downstream (in Rails cache, for example)\r\n- Make `Throttle#request!` return the new state if there was no exception raised","shortMessageHtmlLink":"Prepare Pecorino::Throttle for caching support (#16)"}},{"before":null,"after":"0ba613d4e4e499874c9c4b5360402f3907886009","ref":"refs/heads/pass-state-in-exception","pushedAt":"2024-02-11T17:05:11.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Pass state in the Throttled exception","shortMessageHtmlLink":"Pass state in the Throttled exception"}},{"before":null,"after":"6d890b048767774a19b01fe8d161222e1aab137f","ref":"refs/heads/add-throttled-method","pushedAt":"2024-02-11T13:34:19.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Add `Throttle#throttled`\n\nsince this is a pattern which we turned out to use frequently","shortMessageHtmlLink":"Add Throttle#throttled"}},{"before":"95dfb8edad6e494c89c977b0508c083cdf17e2df","after":"ca4baa9a67ca36d37529771e7284b99ce12e119f","ref":"refs/heads/main","pushedAt":"2024-02-10T23:24:37.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"julik","name":"Julik Tarkhanov","path":"/julik","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/16446?s=80&v=4"},"commit":{"message":"Document circuit breakers","shortMessageHtmlLink":"Document circuit breakers"}}],"hasNextPage":true,"hasPreviousPage":false,"activityType":"all","actor":null,"timePeriod":"all","sort":"DESC","perPage":30,"cursor":"Y3Vyc29yOnYyOpK7MjAyNC0wNS0yMFQwOTozNjo1Ni4wMDAwMDBazwAAAAROoFNT","startCursor":"Y3Vyc29yOnYyOpK7MjAyNC0wNS0yMFQwOTozNjo1Ni4wMDAwMDBazwAAAAROoFNT","endCursor":"Y3Vyc29yOnYyOpK7MjAyNC0wMi0xMFQyMzoyNDozNy4wMDAwMDBazwAAAAP3dnqz"}},"title":"Activity ยท cheddar-me/pecorino"}