TairString's EXINCRBY command enforces hard upper and lower bounds atomically — no Lua scripts required for simple cases. This makes it a direct fit for flash sale inventory tracking and rate limiting, where exceeding a threshold has real consequences.
How it works
EXINCRBY and EXINCRBYFLOAT extend the native Redis INCRBY and INCRBYFLOAT commands with additional options, including MIN and MAX:
| Option | Description |
|---|---|
MIN | Rejects the operation if the result would fall below this value |
MAX | Rejects the operation if the result would exceed this value |
EX | Sets expiry in seconds |
NX | Sets the value only if the key does not exist |
VER | Version check for optimistic locking |
KEEPTTL | Preserves the existing TTL |
When the bound is violated, EXINCRBY returns "increment or decrement would overflow" instead of updating the key. Handle this response as a signal to stop accepting the request — no secondary check needed.
Each EXINCRBY call is atomic. There is no window between the read and write where two concurrent requests could both see the same remaining value.
TairString supports all native Redis String features except bit operations.
For the full command reference, see TairString commands.
When to use bounded counters
Use EXINCRBY with MIN/MAX when you need a hard threshold that must never be crossed:
| Scenario | Approach | Why bounded counters fit |
|---|---|---|
| Flash sale inventory | Decrement with MIN 0 | Stock can never go below zero; no overselling possible |
| Concurrent request cap | Increment with MAX N | Active requests can never exceed N |
| Login attempt limiting | Increment with MAX N + EX | Bound resets after the window expires |
| Password change rate limiting | Increment with MAX N + EX | Prevents credential stuffing at the counter level |
Compared to native Redis `INCRBY` with Lua: Native strings require a Lua script to read, compare, and conditionally update in one atomic step. EXINCRBY handles this in a single command, reducing code complexity and round-trips. Use native strings with Lua if you need more complex conditional logic that goes beyond a fixed min/max threshold.
Flash sale inventory control
To prevent overselling, set the initial stock count as the TairString value and decrement with MIN 0. Once stock reaches zero, EXINCRBY rejects further decrements automatically.
if(EXINCRBY(key_iphone, -1, MIN:0) == "would overflow")
run_out();Rate limiting and throttling
Use MAX to cap the counter at an upper bound. The following example limits concurrent requests to 1,000:
if(EXINCRBY(rate_limitor, 1, MAX:1000) == "would overflow")
traffic_control();This pattern applies to any scenario with a numeric threshold: queries per second (QPS), concurrent connections, login attempts, or password change frequency.
Java example: concurrent request limiter
The following tryAcquire method is thread-safe. It increments the counter within an expiry window and returns false once the upper bound is reached.
/**
* Attempts to acquire a slot within the rate limit window.
*
* @param key The rate limit key
* @param upperBound The maximum allowed count
* @param interval The time window in seconds
* @return true if the slot was acquired; false if the limit is reached
*/
public static boolean tryAcquire(String key, int upperBound, int interval) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.eval("if redis.call('exists', KEYS[1]) == 1 "
+ "then return redis.call('EXINCRBY', KEYS[1], '1', 'MAX', ARGV[1], 'KEEPTTL') "
+ "else return redis.call('EXSET', KEYS[1], 0, 'EX', ARGV[2]) end",
Arrays.asList(key), Arrays.asList(String.valueOf(upperBound), String.valueOf(interval)));
return true;
} catch (Exception e) {
if (e.getMessage().contains("increment or decrement would overflow")) {
return false;
}
e.printStackTrace();
}
return false;
}The Lua script combines two operations atomically:
If the key exists: increment with
EXINCRBY, applyingMAXand preserving the existing TTL withKEEPTTL.If the key does not exist: initialize it to
0withEXSETand set the expiry window withEX.
Handling failures in production: The tryAcquire method catches overflow as an expected control-flow signal. For other exceptions — such as a Redis connection failure — the method currently logs the error and returns false, which fails closed (blocks requests). Decide whether your application should fail open (allow requests through) or fail closed (block requests) when TairString is unavailable, and update the exception handler accordingly.
What's next
TairString commands — full reference for
EXINCRBY,EXINCRBYFLOAT,EXSET, and all supported options