GS2-Limit Transaction Actions
Combining actions, and concurrency
The background common to every service is collected in Combining Transaction Actions. Read that first; the rest of this section is what GS2-Limit adds to it.
The transaction actions of GS2-Limit address one counter, identified by the combination of namespace, user, limit model, and counter name.
| Operation | Repeated in one transaction | Across a nested transaction | Boundary that separates targets |
|---|---|---|---|
Counting up and downCountUpByUserId CountDownByUserId | Any mix; combined and the values added up. Count ups with differing maxValue are rejected when the transaction is issued | Added up | namespace, user, limit model, counter name |
Deleting a counterDeleteCounterByUserId | Combined | Fails | namespace, user, limit model, counter name |
VerifyingVerifyCounterByUserId | The thresholds are added up, so writing exactly the same check twice doubles it. Checks with differing counts are each judged | No collision, because it only reads | counter, verify type, count |
Counting up and down are one row because both are written as a pure increment on the same value; mixing them is fine. The result is judged against the total after combining. The count cannot go below zero and cannot exceed the limit set on the limit model, so a count up that fits on its own can still be rejected when combined with another one.
Count ups with differing upper limits cannot be placed against the same counter. Adding them up while the limits disagree would either drop a stricter limit or have a permissive increment rejected by a stricter one, so count ups with differing maxValue against one counter are rejected when the transaction is issued. Specify them separately.
Deleting a counter removes the counter itself rather than changing its value, so it cannot sit alongside anything else on that counter. Split the transaction where you want to reset a counter and then start counting again.
Verify actions look at the counter as of the start of the transaction. You cannot verify a count that is reached by the same transaction.
Take care with nested transactions
Counting up and down are safe across a nested transaction: they are applied together as one update whichever route they arrive by.
Deleting a counter is not. A deletion arriving from the inside while the same counter is counted from the outside makes the transaction fail.
If you want to avoid these restrictions
Counting down and deleting a counter are acquire actions; counting up is a consume action. Turning acquireActionUseJobQueue on clears a collision between a deletion and a count down, but a deletion together with a count up needs enableAtomicCommit turned off.
Concurrency and retries
Counting up and down do not conflict however many concurrent requests overlap, as long as the result stays within range. A conflict (409) is returned when concurrent count ups together exceed the limit, or when concurrent count downs together take the count below zero; retrying re-evaluates against the latest count.
A counter is reset on a schedule. A request that lands exactly on a reset boundary may return a conflict (409); retrying after the reset has settled will succeed.
Verify Action
Gs2Limit:VerifyCounterByUserId
Verify Counter value by User ID
Verifies that the specified user’s counter value satisfies the given condition. Supports 6 comparison operators: less, lessEqual, greater, greaterEqual, equal, notEqual.
Quantity specification supported: NO
| Type | Condition | Required | Default | Value Limits | Description | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||||||||||||||||
| userId | string | ✓ | ~ 128 chars | User ID Specify #{userId} to substitute the currently logged-in user’s ID. | ||||||||||||||||
| limitName | string | ✓ | ~ 128 chars | Usage Limit Model Name The name of the limit model that this counter belongs to. Determines the reset schedule (daily, weekly, monthly, etc.) applied to this counter’s value. | ||||||||||||||||
| counterName | string | ✓ | ~ 128 chars | Counter Name A unique identifier for this counter within the limit model. Multiple counters can share the same limit model with different names, allowing separate usage tracking (e.g., one counter per quest or per product) without creating separate limit models. | ||||||||||||||||
| verifyType | string (enum) enum { “less”, “lessEqual”, “greater”, “greaterEqual”, “equal”, “notEqual” } | ✓ | Type of verification
| |||||||||||||||||
| count | int | 0 | 0 ~ 2147483646 | Count Value The current usage count for this counter. Incremented by the countUp operation and compared against the maximum value specified at that time. Automatically reset to zero when the limit model’s reset timing is reached. | ||||||||||||||||
| multiplyValueSpecifyingQuantity | bool | true | Whether to multiply the value used for verification when specifying the quantity | |||||||||||||||||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2Limit:VerifyCounterByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"userId": "[string]User ID",
"limitName": "[string]Usage Limit Model Name",
"counterName": "[string]Counter Name",
"verifyType": "[string]Type of verification",
"count": "[int]Count Value",
"multiplyValueSpecifyingQuantity": "[bool]Whether to multiply the value used for verification when specifying the quantity",
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2Limit:VerifyCounterByUserId
request:
namespaceName: "[string]Namespace name"
userId: "[string]User ID"
limitName: "[string]Usage Limit Model Name"
counterName: "[string]Counter Name"
verifyType: "[string]Type of verification"
count: "[int]Count Value"
multiplyValueSpecifyingQuantity: "[bool]Whether to multiply the value used for verification when specifying the quantity"
timeOffsetToken: "[string]Time offset token"transaction.service("limit").verify.verify_counter_by_user_id({
namespaceName="[string]Namespace name",
userId="[string]User ID",
limitName="[string]Usage Limit Model Name",
counterName="[string]Counter Name",
verifyType="[string]Type of verification",
count="[int]Count Value",
multiplyValueSpecifyingQuantity="[bool]Whether to multiply the value used for verification when specifying the quantity",
timeOffsetToken="[string]Time offset token",
})Consume Action
Gs2Limit:CountUpByUserId
Count-up by User ID
Increments the specified user’s counter by the specified count-up value. If maxValue is specified, the counter will not exceed that limit; an Overflow error is returned if the operation would exceed the maximum. If the counter does not yet exist, it is automatically created.
Quantity specification supported: YES
Reversible action: YES
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| limitName | string | ✓ | ~ 128 chars | Usage Limit Model Name The name of the limit model that this counter belongs to. Determines the reset schedule (daily, weekly, monthly, etc.) applied to this counter’s value. | ||
| counterName | string | ✓ | ~ 128 chars | Counter Name A unique identifier for this counter within the limit model. Multiple counters can share the same limit model with different names, allowing separate usage tracking (e.g., one counter per quest or per product) without creating separate limit models. | ||
| userId | string | ✓ | ~ 128 chars | User ID Specify #{userId} to substitute the currently logged-in user’s ID. | ||
| countUpValue | int | 1 | 1 ~ 2147483646 | Amount to count up | ||
| maxValue | int | 1 ~ 2147483646 | Maximum value allowed to count up | |||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2Limit:CountUpByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"limitName": "[string]Usage Limit Model Name",
"counterName": "[string]Counter Name",
"userId": "[string]User ID",
"countUpValue": "[int]Amount to count up",
"maxValue": "[int]Maximum value allowed to count up",
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2Limit:CountUpByUserId
request:
namespaceName: "[string]Namespace name"
limitName: "[string]Usage Limit Model Name"
counterName: "[string]Counter Name"
userId: "[string]User ID"
countUpValue: "[int]Amount to count up"
maxValue: "[int]Maximum value allowed to count up"
timeOffsetToken: "[string]Time offset token"transaction.service("limit").consume.count_up_by_user_id({
namespaceName="[string]Namespace name",
limitName="[string]Usage Limit Model Name",
counterName="[string]Counter Name",
userId="[string]User ID",
countUpValue="[int]Amount to count up",
maxValue="[int]Maximum value allowed to count up",
timeOffsetToken="[string]Time offset token",
})Acquire Action
Gs2Limit:CountDownByUserId
Count-down by User ID
Decrements the specified user’s counter by the specified count-down value. The counter value will not go below 0.
Quantity specification supported: YES
Reversible action: YES
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| limitName | string | ✓ | ~ 128 chars | Usage Limit Model Name The name of the limit model that this counter belongs to. Determines the reset schedule (daily, weekly, monthly, etc.) applied to this counter’s value. | ||
| counterName | string | ✓ | ~ 128 chars | Counter Name A unique identifier for this counter within the limit model. Multiple counters can share the same limit model with different names, allowing separate usage tracking (e.g., one counter per quest or per product) without creating separate limit models. | ||
| userId | string | ✓ | ~ 128 chars | User ID Specify #{userId} to substitute the currently logged-in user’s ID. | ||
| countDownValue | int | 1 | 1 ~ 2147483646 | Amount to count down | ||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2Limit:CountDownByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"limitName": "[string]Usage Limit Model Name",
"counterName": "[string]Counter Name",
"userId": "[string]User ID",
"countDownValue": "[int]Amount to count down",
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2Limit:CountDownByUserId
request:
namespaceName: "[string]Namespace name"
limitName: "[string]Usage Limit Model Name"
counterName: "[string]Counter Name"
userId: "[string]User ID"
countDownValue: "[int]Amount to count down"
timeOffsetToken: "[string]Time offset token"transaction.service("limit").acquire.count_down_by_user_id({
namespaceName="[string]Namespace name",
limitName="[string]Usage Limit Model Name",
counterName="[string]Counter Name",
userId="[string]User ID",
countDownValue="[int]Amount to count down",
timeOffsetToken="[string]Time offset token",
})Gs2Limit:DeleteCounterByUserId
Delete Counter by User ID
Deletes the specified user’s counter, resetting the usage count. This effectively removes the limit restriction for this counter, allowing the user to start counting from 0 again.
Quantity specification supported: NO
Reversible action: NO
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| limitName | string | ✓ | ~ 128 chars | Usage Limit Model Name The name of the limit model that this counter belongs to. Determines the reset schedule (daily, weekly, monthly, etc.) applied to this counter’s value. | ||
| userId | string | ✓ | ~ 128 chars | User ID Specify #{userId} to substitute the currently logged-in user’s ID. | ||
| counterName | string | ✓ | ~ 128 chars | Counter Name A unique identifier for this counter within the limit model. Multiple counters can share the same limit model with different names, allowing separate usage tracking (e.g., one counter per quest or per product) without creating separate limit models. | ||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2Limit:DeleteCounterByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"limitName": "[string]Usage Limit Model Name",
"userId": "[string]User ID",
"counterName": "[string]Counter Name",
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2Limit:DeleteCounterByUserId
request:
namespaceName: "[string]Namespace name"
limitName: "[string]Usage Limit Model Name"
userId: "[string]User ID"
counterName: "[string]Counter Name"
timeOffsetToken: "[string]Time offset token"transaction.service("limit").acquire.delete_counter_by_user_id({
namespaceName="[string]Namespace name",
limitName="[string]Usage Limit Model Name",
userId="[string]User ID",
counterName="[string]Counter Name",
timeOffsetToken="[string]Time offset token",
})