I spent a fair bit of time debating whether to re-invent the wheel here. I'm intimately familiar with the functionality introduced in .NET 7, and I happen to think is very well thought out and an elegant approach to this problem. There wasn't a solution, therefore, that didn't feel like me simply backporting/re-implementing that approach. I don't believe it is particularly useful to you to see if I can successfully backport functionality when our preference should be to stand on the shoulders of dedicated maintainers anyways. I made the decision, therefore, to showcase, instead, how I would approach extending the existing functionality to allow for the stated rate limiting requirements.
I don't believe that a single rate limiting class should be responsible for multiple rules. That, to me, violates the single responsibility principal. In order to accommodate rules that wouldn't always be applied (i.e. a US based token needs to bypass a time since last call limiter) I implemented a predicated limiter built on top of the existing partitioned limiter functionality. This allows for using the CreateChain function to build a ruleset in which each limiter can decide whether its rule applies to a given request.
Microsoft's out of the box functionality also does not include a limiter for time since last request limiting. Technically, the fixed window limiter, configured with a small window and a single permit limit could be used to cover this use case, but there is value in being clear and explicit with desired functionality. One would generally have to logic through that configuration to figure out the desired outcome, and that is wasted time when an explicit limiter can be implemented that is clearer in its purpose is to limit requests to a single request per allowed period.
Ultimately, I recognize that this is not technically entirely responsive to the challenge prompt. I'm comfortable standing by that decision, as I would take the same approach in any on-the-job challenge as well. If a solution exists that is close enough to the stated requirements that I can either extend the functionality to meet them or modify the requirements to make it so the pre-built functionality can suffice, the vast majority of the time that is the approach I would advocate for.
I spent a fair bit of time debating whether to re-invent the wheel here. I'm intimately familiar with the functionality introduced in .NET 7, and I happen to think is very well thought out and an elegant approach to this problem. There wasn't a solution, therefore, that didn't feel like me simply backporting/re-implementing that approach. I don't believe it is particularly useful to you to see if I can successfully backport functionality when our preference should be to stand on the shoulders of dedicated maintainers anyways. I made the decision, therefore, to showcase, instead, how I would approach extending the existing functionality to allow for the stated rate limiting requirements.
I don't believe that a single rate limiting class should be responsible for multiple rules. That, to me, violates the single responsibility principal. In order to accommodate rules that wouldn't always be applied (i.e. a US based token needs to bypass a time since last call limiter) I implemented a predicated limiter built on top of the existing partitioned limiter functionality. This allows for using the
CreateChain
function to build a ruleset in which each limiter can decide whether its rule applies to a given request.Microsoft's out of the box functionality also does not include a limiter for time since last request limiting. Technically, the fixed window limiter, configured with a small window and a single permit limit could be used to cover this use case, but there is value in being clear and explicit with desired functionality. One would generally have to logic through that configuration to figure out the desired outcome, and that is wasted time when an explicit limiter can be implemented that is clearer in its purpose is to limit requests to a single request per allowed period.
Ultimately, I recognize that this is not technically entirely responsive to the challenge prompt. I'm comfortable standing by that decision, as I would take the same approach in any on-the-job challenge as well. If a solution exists that is close enough to the stated requirements that I can either extend the functionality to meet them or modify the requirements to make it so the pre-built functionality can suffice, the vast majority of the time that is the approach I would advocate for.