Skip to content

Commit

Permalink
Adds rate limit service, basic configuration for bucket and quotas.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulbrejla committed Dec 1, 2023
1 parent e9822cf commit 61f5db3
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ dependencies {
implementation("io.springfox:springfox-boot-starter:3.0.0")
implementation('io.springfox:springfox-swagger-ui:3.0.0')
implementation("org.eclipse.jgit:org.eclipse.jgit:6.3.0.202209071007-r")
implementation("com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0")
// Foundation
implementation('org.webjars:foundation:6.4.3')

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.paulbrejla.holidays.application.api

import io.github.bucket4j.Bucket

interface RateLimitService {
fun resolveBucket(bucketId: String): Bucket
fun fetchBucket(bucketId: String): Bucket?
fun isWithinQuota(maxRequests: Int, currentRequests: Int): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package de.paulbrejla.holidays.application.impl

import de.paulbrejla.holidays.application.api.RateLimitService
import io.github.bucket4j.Bandwidth
import io.github.bucket4j.Bucket
import io.github.bucket4j.Refill
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import java.time.Duration
import java.util.concurrent.ConcurrentHashMap

@Component("rateLimitService")
class GlobalRateLimitServiceImpl : RateLimitService {
// For now we create one global bucket that all requests consume from.
@Value("\${rateLimit.globalBucket.id}")
var globalBucketId: String = ""

@Value("\${rateLimit.globalBucket.capacity}")
var globalBucketCapacity: Long = 0


private var buckets: MutableMap<String, Bucket> = ConcurrentHashMap<String, Bucket>()
override fun resolveBucket(bucketId: String): Bucket {
return if (buckets.containsKey(bucketId)) {
buckets[bucketId]!!
} else {
createBucket().let {
buckets[bucketId] = it
it
}
}
}

override fun fetchBucket(bucketId: String): Bucket? {
return buckets[bucketId]
}

override fun isWithinQuota(maxRequests: Int, currentRequests: Int): Boolean {
TODO("Not yet implemented")
}

/**
* We only allow 1000 requests per hour from now on. These 1000 requests are refilled when the new
* hour starts.
*/
private fun createBucket(): Bucket {
return Bucket.builder()
.addLimit(
Bandwidth.classic(
globalBucketCapacity,
Refill.intervally(globalBucketCapacity, Duration.ofHours(1))
)
)
.build()
}
}
8 changes: 6 additions & 2 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ spring:
enabled: false
path: /h2-console
server:
port: ${APPLICATION_PORT:80}
port: ${SERVER_PORT:80}
loader:
source: ${LOADER_SOURCE}
remoteURL: ${LOADER_REMOTE_URL}
branch: ${LOADER_BRANCH}
filePath: ${LOADER_FILE_PATH}
authToken: ${LOADER_AUTH_TOKEN}
authToken: ${LOADER_AUTH_TOKEN}
rateLimit:
globalBucket:
id: ${RATE_LIMIT_GLOBAL_BUCKET_ID:global}
capacity: ${RATE_LIMIT_GLOBAL_BUCKET_CAPACITY:500}

0 comments on commit 61f5db3

Please sign in to comment.