Skip to content

Commit 32cec8b

Browse files
authored
DEV: (cmds) update INCREX command page for recent API change (#3350)
* DEV: (cmds) update INCREX command page for recent API change * Address reviewer's concerns * Address more of the reviewer's comments
1 parent 9f37383 commit 32cec8b

2 files changed

Lines changed: 58 additions & 77 deletions

File tree

content/commands/increx.md

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,13 @@ arguments:
1717
name: increment
1818
optional: true
1919
type: oneof
20-
- arguments:
21-
- name: fail
22-
token: FAIL
23-
type: pure-token
24-
- name: sat
25-
token: SAT
26-
type: pure-token
27-
- name: reject
28-
token: REJECT
29-
type: pure-token
30-
name: overflow-block
20+
- name: saturate
3121
optional: true
32-
summary: Out-of-bounds policy; defaults to FAIL. Missing LBOUND/UBOUND default to
33-
the type limits (LLONG_MIN/LLONG_MAX for BYINT, -LDBL_MAX/LDBL_MAX for BYFLOAT).
34-
token: OVERFLOW
35-
type: oneof
22+
summary: Saturate the result to LBOUND/UBOUND (or the type limits when no explicit
23+
bound is given) when out of bounds. Without this option, out-of-bounds operations
24+
are rejected and reply [current_value, 0].
25+
token: SATURATE
26+
type: pure-token
3627
- name: lowerbound
3728
optional: true
3829
summary: Integer when used with BYINT, floating-point when used with BYFLOAT.
@@ -115,17 +106,16 @@ reply_schema:
115106
since: 8.8.0
116107
summary: Increments the numeric value of a key by a number and sets its expiration
117108
time. Uses 0 as initial value if the key doesn't exist.
118-
syntax_fmt: "INCREX key [BYFLOAT\_float | BYINT\_integer]\n\
119-
\ [LBOUND\_lowerbound] [UBOUND\_upperbound] [OVERFLOW\_<FAIL | SAT | REJECT>]\n\
120-
\ [EX\_seconds | PX\_milliseconds| EXAT\_unix-time-seconds | PXAT\_unix-time-milliseconds | PERSIST]\n\
121-
\ [ENX]"
109+
syntax_fmt: "INCREX key [BYFLOAT\_increment | BYINT\_increment]\n\
110+
\ [LBOUND\_lowerbound] [UBOUND\_upperbound] [SATURATE]\n\
111+
\ [EX\_seconds | PX\_milliseconds | EXAT\_unix-time-seconds| PXAT\_unix-time-milliseconds | PERSIST] [ENX]"
122112
title: INCREX
123113
---
124114
Increments or decrements the numeric value stored at `key` by the specified amount, with optional upper/lower bounds and expiration control, in a single atomic operation.
125115
If the key does not exist, it is set to `0` before performing the operation.
126116
An error is returned if the key contains a value of the wrong type or a string that cannot be interpreted as a number.
127117

128-
Unlike [`INCR`]({{< relref "/commands/incr" >}}) and [`INCRBY`]({{< relref "/commands/incrby" >}}), `INCREX` returns an array of two elements: the new value of the key after the increment, and the increment that was actually applied. The `OVERFLOW` option controls what happens when the computed result would fall outside an explicit `LBOUND`/`UBOUND` or the type limits: the command can fail with an error (the default), saturate the result to the bound, or skip the operation.
118+
Unlike [`INCR`]({{< relref "/commands/incr" >}}) and [`INCRBY`]({{< relref "/commands/incrby" >}}), `INCREX` returns an array of two elements: the new value of the key after the increment, and the increment that was actually applied. When the computed result would fall outside an explicit `LBOUND`/`UBOUND` or the type limits, the default is to skip the operation and reply with `[current_value, 0]`, leaving the key and its TTL untouched. The `SATURATE` flag changes this behavior so the result is capped at the bound instead.
129119

130120
## Required arguments
131121

@@ -137,7 +127,7 @@ The name of the key to increment.
137127

138128
## Optional arguments
139129

140-
<details open><summary><code>BYFLOAT float | BYINT integer</code></summary>
130+
<details open><summary><code>BYFLOAT increment | BYINT increment</code></summary>
141131

142132
Specifies the increment amount and type:
143133

@@ -150,23 +140,21 @@ If neither `BYFLOAT` nor `BYINT` is specified, the key is incremented by `1` in
150140

151141
<details open><summary><code>LBOUND lowerbound</code></summary>
152142

153-
Sets a lower bound for the resulting value. If the computed result would fall below `lowerbound`, the behavior is determined by the `OVERFLOW` option. Defaults to `LLONG_MIN` in integer mode or `-LDBL_MAX` in `BYFLOAT` mode. `LBOUND` must be less than or equal to `UBOUND` when both are specified.
143+
Sets a lower bound for the resulting value. If the computed result would fall below `lowerbound`, the operation is skipped and the reply is `[current_value, 0]` (or use the `SATURATE` flag to floor the result at `lowerbound` instead). When omitted, the bound is `LLONG_MIN` in integer mode or `-LDBL_MAX` in `BYFLOAT` mode. `LBOUND` must be less than or equal to `UBOUND` when both are specified.
154144

155145
</details>
156146

157147
<details open><summary><code>UBOUND upperbound</code></summary>
158148

159-
Sets an upper bound for the resulting value. If the computed result would exceed `upperbound`, the behavior is determined by the `OVERFLOW` option. Defaults to `LLONG_MAX` in integer mode or `LDBL_MAX` in `BYFLOAT` mode. `UBOUND` must be greater than or equal to `LBOUND` when both are specified.
149+
Sets an upper bound for the resulting value. If the computed result would exceed `upperbound`, the operation is skipped and the reply is `[current_value, 0]` (or use the `SATURATE` flag to cap the result at `upperbound` instead). When omitted, the bound is `LLONG_MAX` in integer mode or `LDBL_MAX` in `BYFLOAT` mode. `UBOUND` must be greater than or equal to `LBOUND` when both are specified.
160150

161151
</details>
162152

163-
<details open><summary><code>OVERFLOW FAIL | SAT | REJECT</code></summary>
153+
<details open><summary><code>SATURATE</code></summary>
164154

165-
Sets the policy for handling out-of-bounds results. A bound violation includes both exceeding an explicit `LBOUND`/`UBOUND` and overflowing the type limits when no explicit bound is given.
155+
When specified, an out-of-bounds result is capped at `UBOUND` or floored at `LBOUND` (or saturated to the type limits when no explicit bound is given). The second element of the reply reflects the saturated delta. An error is returned if the delta cannot be represented as a 64-bit signed integer in integer mode, or would produce Infinity in `BYFLOAT` mode. Any expiration option is still applied as specified.
166156

167-
* `FAIL` (default): if the computed result would violate a bound, the command returns an error and the key is left unchanged. This matches the existing semantics of [`INCRBY`]({{< relref "/commands/incrby" >}}) and [`INCRBYFLOAT`]({{< relref "/commands/incrbyfloat" >}}) on overflow.
168-
* `SAT`: the result is capped at `UBOUND` or floored at `LBOUND` (or saturated to the type limits when no explicit bound is given). The second element of the reply reflects the saturated delta. An error is returned if the delta cannot be represented as a 64-bit signed integer in integer mode, or would produce Infinity in `BYFLOAT` mode. If the result is saturated, any expiration option is still applied as specified.
169-
* `REJECT`: the operation is skipped. The key value and its TTL are left unchanged, no keyspace notification is fired, and nothing is replicated. The reply is `[current_value, 0]`, allowing the caller to detect the rejection without handling an error. Any expiration option is ignored on the rejected branch.
157+
A bound violation includes both exceeding an explicit `LBOUND`/`UBOUND` and overflowing the type limits when no explicit bound is given.
170158

171159
</details>
172160

@@ -243,27 +231,25 @@ INCREX mykey BYINT 1 PERSIST
243231
TTL mykey
244232
{{% /redis-cli %}}
245233

246-
Compare the three `OVERFLOW` policies when the result would exceed `UBOUND`. The default `FAIL` returns an error, `SAT` caps the result at the bound, and `REJECT` leaves the key untouched and reports a zero delta:
234+
Compare the default out-of-bounds behavior with `SATURATE` when the result would exceed `UBOUND`. By default the key is left untouched and the reply reports a zero delta; with `SATURATE` the result is capped at the bound and the reply reflects the saturated delta:
247235

248236
{{% redis-cli %}}
249237
SET mykey 99
250238
INCREX mykey BYINT 5 UBOUND 100
251239
SET mykey 99
252-
INCREX mykey BYINT 5 UBOUND 100 OVERFLOW SAT
253-
SET mykey 99
254-
INCREX mykey BYINT 5 UBOUND 100 OVERFLOW REJECT
240+
INCREX mykey BYINT 5 UBOUND 100 SATURATE
255241
{{% /redis-cli %}}
256242

257243
## Pattern: window counter rate limiter
258244

259245
A common rate-limiting pattern requires atomically incrementing a counter and setting its expiration. With plain [`INCR`]({{< relref "/commands/incr" >}}) and [`EXPIRE`]({{< relref "/commands/expire" >}}), this typically requires a Lua script to be atomic.
260246

261-
`INCREX` requires a single native command. `UBOUND` enforces the rate cap, `OVERFLOW REJECT` skips the operation once the cap is reached, and `ENX` ensures that a new window with the correct duration is created if the previous one has expired; if a window already exists, it won't be extended. When the counter has already reached the cap, `actual_increment` is `0`, giving the caller immediate feedback without extra reads or error handling:
247+
`INCREX` requires a single native command. `UBOUND` enforces the rate cap — by default, once the cap is reached the operation is skipped — and `ENX` ensures that a new window with the correct duration is created if the previous one has expired; if a window already exists, it won't be extended. When the counter has already reached the cap, `actual_increment` is `0`, giving the caller immediate feedback without extra reads or error handling:
262248

263249
```python
264250
new_val, actual_incr = redis.execute_command(
265251
"INCREX", f"ratelimit:{user_id}",
266-
"BYINT", 1, "UBOUND", 100, "OVERFLOW", "REJECT",
252+
"BYINT", 1, "UBOUND", 100,
267253
"EX", 60, "ENX",
268254
)
269255
if actual_incr == 0:
@@ -284,17 +270,17 @@ if actual_incr == 0:
284270

285271
[Array reply]({{< relref "/develop/reference/protocol-spec#arrays" >}}): a two-element array:
286272

287-
1. **New value** — the value of the key after the increment, or the unchanged current value under `OVERFLOW REJECT`.
288-
2. **Actual increment** — the increment that was actually applied. May differ from the requested increment when `OVERFLOW SAT` saturates the result to a bound, and is always `0` when `OVERFLOW REJECT` skipped the operation.
273+
1. **New value** — the value of the key after the increment, or the unchanged current value when an out-of-bounds result caused the operation to be skipped.
274+
2. **Actual increment** — the increment that was actually applied. May differ from the requested increment when `SATURATE` caps the result at a bound, and is always `0` when an out-of-bounds result caused the operation to be skipped.
289275

290276
Both elements are [Integer replies]({{< relref "/develop/reference/protocol-spec#integers" >}}) in integer mode (default or `BYINT`), or [Bulk string replies]({{< relref "/develop/reference/protocol-spec#bulk-strings" >}}) representing the float values in `BYFLOAT` mode.
291277

292278
-tab-sep-
293279

294280
[Array reply]({{< relref "/develop/reference/protocol-spec#arrays" >}}): a two-element array:
295281

296-
1. **New value** — the value of the key after the increment, or the unchanged current value under `OVERFLOW REJECT`.
297-
2. **Actual increment** — the increment that was actually applied. May differ from the requested increment when `OVERFLOW SAT` saturates the result to a bound, and is always `0` when `OVERFLOW REJECT` skipped the operation.
282+
1. **New value** — the value of the key after the increment, or the unchanged current value when an out-of-bounds result caused the operation to be skipped.
283+
2. **Actual increment** — the increment that was actually applied. May differ from the requested increment when `SATURATE` caps the result at a bound, and is always `0` when an out-of-bounds result caused the operation to be skipped.
298284

299285
Both elements are [Integer replies]({{< relref "/develop/reference/protocol-spec#integers" >}}) in integer mode (default or `BYINT`), or [Double replies]({{< relref "/develop/reference/protocol-spec#doubles" >}}) in `BYFLOAT` mode.
300286

0 commit comments

Comments
 (0)