GS2-Dictionary 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-Dictionary adds to it.
The transaction actions of GS2-Dictionary address the dictionary of one user, that is, the list of entries they have collected. It is identified by the combination of namespace and user, and adding or deleting entries rewrites the list as a whole.
| Operation | Repeated in one transaction | Across a nested transaction | Boundary that separates targets |
|---|---|---|---|
Adding entriesAddEntriesByUserId | Combined, with entry names concatenated and duplicates removed | Fails | namespace, user |
Deleting entriesDeleteEntriesByUserId | Combined, with entry names concatenated and duplicates removed | Fails | namespace, user |
Verifying an entryVerifyEntryByUserId | First wins | No collision, because it only reads | entry, verify type |
Adding and deleting are separate rows sharing a boundary, so a transaction cannot both add and delete against one dictionary. Split the transaction.
Additions are combined with duplicates removed, so the same entry may appear in several actions. The limit of 100 entry names is judged after the duplicates are removed.
Where an addition or a deletion happens not to change the dictionary at all, because every entry was already collected or none of them was held, the two can pass together. This depends on the user’s state at run time, so do not design around it.
Verify actions look at the dictionary as of the start of the transaction. You cannot verify with have an entry that the same transaction added, nor with havent one it deleted.
Take care with nested transactions
Even two additions, which would have been combined into one if written side by side, make the transaction fail when one of them arrives from the inside. Adding the same entry by both routes behaves the same way.
If you want to avoid these restrictions
Adding entries is an acquire action and deleting them is a consume action. Turning acquireActionUseJobQueue on clears a collision with an addition arriving from the inside, but an addition together with a deletion needs enableAtomicCommit turned off.
Concurrency and retries
Where several requests update the same user’s dictionary at the same time, the one confirmed later returns a conflict (409). Nothing is wrong with the dictionary, so retrying will succeed.
It gets more likely the more concurrently you issue requests that update one user’s dictionary. Gathering additions and deletions into one transaction, or serialising updates per user, both help.
Verify Action
Gs2Dictionary:VerifyEntryByUserId
Verify Entry by User ID
Verifies whether the specified user has or has not collected a specific entry. The verify type specifies the condition: ‘have’ checks that the user has the entry, ‘havent’ checks that the user does not have it. If the verification fails, an error is returned.
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. | ||||||||
| entryModelName | string | ✓ | ~ 128 chars | Entry Model name Unique Entry Model name. Specified using alphanumeric characters, hyphen (-), underscore (_), and period (.). | ||||||||
| verifyType | string (enum) enum { “havent”, “have” } | ✓ | Type of verification
| |||||||||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2Dictionary:VerifyEntryByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"userId": "[string]User ID",
"entryModelName": "[string]Entry Model name",
"verifyType": "[string]Type of verification",
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2Dictionary:VerifyEntryByUserId
request:
namespaceName: "[string]Namespace name"
userId: "[string]User ID"
entryModelName: "[string]Entry Model name"
verifyType: "[string]Type of verification"
timeOffsetToken: "[string]Time offset token"transaction.service("dictionary").verify.verify_entry_by_user_id({
namespaceName="[string]Namespace name",
userId="[string]User ID",
entryModelName="[string]Entry Model name",
verifyType="[string]Type of verification",
timeOffsetToken="[string]Time offset token",
})Consume Action
Gs2Dictionary:DeleteEntriesByUserId
Delete entries by User ID
Removes specific Entry from the specified user’s dictionary by specifying a list of entry model names. Multiple entries can be deleted at once in a batch operation. The returned list contains the entries that were actually deleted.
Quantity specification supported: NO
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. | ||
| entryModelNames | List<string> | [] | 0 ~ 100 items | List of Entry Model names | ||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2Dictionary:DeleteEntriesByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"userId": "[string]User ID",
"entryModelNames": [
"[string]Entry Model name"
],
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2Dictionary:DeleteEntriesByUserId
request:
namespaceName: "[string]Namespace name"
userId: "[string]User ID"
entryModelNames:
- "[string]Entry Model name"
timeOffsetToken: "[string]Time offset token"transaction.service("dictionary").consume.delete_entries_by_user_id({
namespaceName="[string]Namespace name",
userId="[string]User ID",
entryModelNames={
"[string]Entry Model name"
},
timeOffsetToken="[string]Time offset token",
})Acquire Action
Gs2Dictionary:AddEntriesByUserId
Add entries by User ID
Registers one or more entry model names to the specified user’s dictionary. Multiple entry model names can be specified at once in a batch operation. If an entry has already been registered, it is silently skipped without causing an error. The returned list contains only the entries that were newly added.
Quantity specification supported: NO
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. | ||
| entryModelNames | List<string> | [] | 0 ~ 100 items | List of Entry Model names | ||
| timeOffsetToken | string | ~ 1024 chars | Time offset token |
{
"action": "Gs2Dictionary:AddEntriesByUserId",
"request": {
"namespaceName": "[string]Namespace name",
"userId": "[string]User ID",
"entryModelNames": [
"[string]Entry Model name"
],
"timeOffsetToken": "[string]Time offset token"
}
}action: Gs2Dictionary:AddEntriesByUserId
request:
namespaceName: "[string]Namespace name"
userId: "[string]User ID"
entryModelNames:
- "[string]Entry Model name"
timeOffsetToken: "[string]Time offset token"transaction.service("dictionary").acquire.add_entries_by_user_id({
namespaceName="[string]Namespace name",
userId="[string]User ID",
entryModelNames={
"[string]Entry Model name"
},
timeOffsetToken="[string]Time offset token",
})