createDefaultProxied

fun createDefaultProxied(scope: RateLimitScope, proxyManager: ProxyManager<String>, configurationSupplier: BucketConfigurationSupplier, deleteOnRefill: Boolean = true): RateLimiter(source)

Creates a RateLimiter implementation which retrieves its buckets using proxyManager, see DefaultRateLimitHandler and ProxyBucketAccessor for details.

Requirements

The proxy requires a String to store the bucket key.

Using a database

First, install the PostgreSQL module for Bucket4J (recommended, Bucket4J supports other RDBMs), then, use the following DDL to create the tables storing the buckets, I recommend you put this in a migration script, using Flyway:

CREATE TABLE bucket(id TEXT PRIMARY KEY, state BYTEA, expires_at BIGINT);

Note:

  • You can use any RDBMs supported by Bucket4J, as you are passing the DataSource directly.

  • You may need to set the default schema on your DataSource to public, or the schema you store the table in.

Anything else

You can also use anything that accepts a String as your bucket key, such as JCache and Redis, see the Bucket4J docs for more details.

Example

@BService
class ProxyManagerProvider {
@BService
open fun proxyManager(hikariSourceSupplier: HikariSourceSupplier): ProxyManager<String> {
// Create a proxy to manager buckets, persisting with PostgreSQL,
// see https://bucket4j.com/8.14.0/toc.html#postgresqlselectforupdatebasedproxymanager
return Bucket4jPostgreSQL.selectForUpdateBasedBuilder(hikariSourceSupplier.source)
// Bucket expiration, needs to be triggered manually,
// see https://bucket4j.com/8.14.0/toc.html#expiration-policy
.expirationAfterWrite(ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(1.minutes.toJavaDuration()))
// RateLimiter#createDefaultProxied uses a String key
.primaryKeyMapper(PreparedStatement::setString)
.build()
}
}
@Command
class SlashPersistentRateLimit(private val proxyManager: ProxyManager<String>) : ApplicationCommand(), GlobalApplicationCommandProvider {
fun onSlashPersistentRateLimit(event: GuildSlashEvent) {
event.reply_("Hi", ephemeral = true).queue()
}

override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
manager.slashCommand("persistent_rate_limit", function = ::onSlashPersistentRateLimit) {
// Allow using the command once every hour
// NOTE: this won't take effect if you are the bot owner
val cooldown = Buckets.ofCooldown(1.hours)
// Apply limit on each user, regardless or guild/channel
val rateLimiter = RateLimiter.createDefaultProxied(RateLimitScope.USER, proxyManager, cooldown.toSupplier())
// Register anonymous rate limit, only on this command
rateLimit(rateLimiter)
}
}
}

Parameters

scope

Scope of the rate limit, see RateLimitScope values.

proxyManager

The proxy supplying buckets from a key, based on the scope

configurationSupplier

A supplier of BucketConfiguration, describing the rate limits

deleteOnRefill

Whether the rate limit message should be deleted after expiring

See also