GS2-AdReward 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-AdReward adds to it.
The transaction actions of GS2-AdReward address the single point balance that exists per namespace and per user.
| Operation | Repeated in one transaction | Across a nested transaction | Boundary that separates targets |
|---|---|---|---|
Acquiring pointsAcquirePointByUserId | Combined, and the points are added up | Added up | namespace, user |
Consuming pointsConsumePointByUserId | Combined, and the balance is checked against the total | Added up, except that a total consumption beyond the balance returns a conflict (409) that a retry cannot clear while the balance stays short | namespace, user |
Both rows are written as a pure increment on the same balance, so an acquire and a consume may be placed together and each is applied. Acquiring 100 and acquiring 50 is handled as one acquire of 150. Against a balance of 100, consuming 60 and consuming 30 leaves 10; consuming 60 and acquiring 200 leaves 240.
Where the total consumption exceeds the balance at the start of the transaction, an insufficient points error (400) is returned and no part of the consumption is applied.
Points acquired in a transaction cannot pay for a consume action in that same transaction. Consume actions always run before acquire actions, so only the balance at the start of the transaction is available. Split the transaction where you need that.
Take care with nested transactions
GS2-AdReward tolerates this. Increases and decreases arriving from separate transactions are still applied together as one update to the balance, so they do not conflict. The only exception is when the consumption arriving through these separate routes adds up to more than the balance: the transaction is then rejected as a conflict (409) rather than as an insufficient points error (400), and the balance is left unchanged. Retrying does not help unless the balance has grown in the meantime.
If you want to avoid these restrictions
The one restriction above comes from the order of execution. Neither enableAtomicCommit nor acquireActionUseJobQueue changes that order, so neither of them lifts it. Split the transaction if you want acquired points to be spent.
Concurrency and retries
Concurrent acquires, and an acquire running concurrently with a consume, do not conflict in principle, because each increase and decrease is applied reliably.
When updates to the same point balance are concentrated in a short period, a transient conflict (409) may be returned. The balance is not the cause, so retrying after a short interval will succeed.
When consume actions in separate transactions run concurrently and their total exceeds the balance, a conflict (409) may be returned. A retry re-evaluates the request against the latest balance, so it succeeds if the balance is sufficient at that point, and returns an insufficient points error (400) if it is not.
Consume Action
Gs2AdReward:ConsumePointByUserId
Consume Point by User ID
Consumes points from the specified user ID and returns the updated point information. An error is returned if the user does not have enough points to cover the requested consumption amount. If a GS2-Script is configured in the Namespace’s consume script settings, the script is executed before consuming points, allowing custom validation or modification of the consumed amount. After the point deduction, a change notification is sent if configured in the Namespace settings.
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 (.). | ||
| userId | string | ✓ | ~ 128 chars | User ID Specify #{userId} to substitute the currently logged-in user’s ID. | ||
| point | long | ✓ | 1 ~ 9223372036854775805 | Consume Points | ||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2AdReward:ConsumePointByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"userId": "[string]User ID",
"point": "[long]Consume Points",
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2AdReward:ConsumePointByUserId
request:
namespaceName: "[string]Namespace name"
userId: "[string]User ID"
point: "[long]Consume Points"
timeOffsetToken: "[string]Time offset token"transaction.service("adReward").consume.consume_point_by_user_id({
namespaceName="[string]Namespace name",
userId="[string]User ID",
point="[long]Consume Points",
timeOffsetToken="[string]Time offset token",
})Acquire Action
Gs2AdReward:AcquirePointByUserId
Acquire Point by User ID
Adds a specified number of points to the specified user ID and returns the updated point information. If the user has no existing point record, a new record is automatically created before adding points. If a GS2-Script is configured in the Namespace’s acquire script settings, the script is executed before acquiring points, allowing custom validation or modification of the acquired amount. After the point addition, a change notification is sent if configured in the Namespace settings.
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 (.). | ||
| userId | string | ✓ | ~ 128 chars | User ID Specify #{userId} to substitute the currently logged-in user’s ID. | ||
| point | long | ✓ | 1 ~ 9223372036854775805 | Acquire Points | ||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2AdReward:AcquirePointByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"userId": "[string]User ID",
"point": "[long]Acquire Points",
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2AdReward:AcquirePointByUserId
request:
namespaceName: "[string]Namespace name"
userId: "[string]User ID"
point: "[long]Acquire Points"
timeOffsetToken: "[string]Time offset token"transaction.service("adReward").acquire.acquire_point_by_user_id({
namespaceName="[string]Namespace name",
userId="[string]User ID",
point="[long]Acquire Points",
timeOffsetToken="[string]Time offset token",
})