GS2-Schedule Transaction Actions

Specification of verify/consume/acquire 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-Schedule adds to it.

The transaction actions of GS2-Schedule address one trigger, identified by the combination of namespace, user, and trigger name. A trigger is rewritten as a whole on every update.

OperationRepeated in one transactionAcross a nested transactionBoundary that separates targetsUnder sequential execution mode
Pulling a trigger
TriggerByUserId
Combined into oneFailsnamespace, user, trigger nameSucceeds even across a nested transaction, but the two are no longer gathered into one: the second pull runs against the trigger the first one left and applies its own triggerStrategy to it
Extending a trigger
ExtendTriggerByUserId
Combined, and the seconds are added upFailsnamespace, user, trigger nameSucceeds even across a nested transaction; the second extend runs against the expiry the first one left, so the seconds still add up
Deleting a trigger
DeleteTriggerByUserId
Combined into oneFailsnamespace, user, trigger nameStill fails. The two are no longer gathered into one, so the second one runs against a trigger that is already gone and is rejected as not found (404)
Verifying a trigger
VerifyTriggerByUserId
Checks that match exactly are gathered into oneNo collision, because it only readstrigger, verify type, elapsed timeNo change; it already succeeds because it only reads
Verifying an event
VerifyEventByUserId
Checks that match exactly are gathered into oneNo collision, because it only readsevent, verify type, userNo change; it already succeeds because it only reads

Pulling, extending, and deleting are three separate rows sharing a boundary, so placing two of them against one trigger collides. Wanting to pull a trigger and then extend it is a common request, but it takes two transactions: extending works from the state at the start of the transaction, so it cannot see a trigger the same transaction pulled. Turning on sequential execution mode (enableSequentialExecution or TransactionSettingV2) lets a pull and an extend sit in one transaction, but not in the order you might expect: the order within a phase is decided by the action name, so ExtendTriggerByUserId always runs before TriggerByUserId. Where the trigger does not exist yet the extend creates it and the pull then applies its own triggerStrategy on top; you cannot pull first and extend the result in the same transaction. Deleting together with a pull or an extend is not resolved: deleting is a consume action and runs first, and a trigger removed and then created again in one transaction is two writes to the same row that cannot be combined (400).

Verify actions look at the state as of the start of the transaction. You cannot verify a trigger that the same transaction pulled, or one it deleted.

Whether an event is running depends on the time offset, which is per user, so an event verification is a different target for each user.

Take care with nested transactions

A trigger is rewritten as a whole, so a trigger pulled from the inside collides with the same trigger extended or deleted from the outside, and the transaction fails. Sequential execution mode does not remove the case where the outside deletes the trigger either: deleting does run first, but the pull that follows then has to create the trigger again, and a delete and a create of the same row in one transaction cannot be combined (400).

If you want to avoid these restrictions

Pulling and extending a trigger are acquire actions; deleting one is a consume action. Turning acquireActionUseJobQueue on clears a collision between a pull and an extend, but a collision with a delete needs enableAtomicCommit turned off.

Concurrency and retries

A trigger is rewritten as a whole with a revision check, so when several requests update the same trigger at the same time, the one confirmed later returns a conflict (409). Nothing is wrong with the request, so retrying will succeed.

A different trigger name is a different target, so requests for different triggers do not conflict.


Verify Action

Gs2Schedule:VerifyTriggerByUserId

Verify the elapsed time since the Trigger was pulled by User ID

Verifies conditions related to the trigger’s state for the specified user. The verifyType can be: notTriggerd, elapsed, or notElapsed. Returns an error if the verification condition is not met.

Quantity specification supported: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
triggerNamestring
~ 128 charsTrigger name
Unique Trigger name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
verifyTypestring (enum)
enum {
  “notTriggerd”,
  “elapsed”,
  “notElapsed”
}
Type of verification
DefinitionDescription
notTriggerdTrigger not pulled
elapsedElapsed time
notElapsedNot elapsed time
elapsedMinutesint{verifyType} in [“elapsed”, “notElapsed”]
✓*
0 ~ 2147483646Elapsed time (minutes)
* Required if verifyType is “elapsed”,“notElapsed”
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Schedule:VerifyTriggerByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "triggerName": "[string]Trigger name",
        "verifyType": "[string]Type of verification",
        "elapsedMinutes": "[int]Elapsed time (minutes)",
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Schedule:VerifyTriggerByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  triggerName: "[string]Trigger name"
  verifyType: "[string]Type of verification"
  elapsedMinutes: "[int]Elapsed time (minutes)"
  timeOffsetToken: "[string]Time offset token"
transaction.service("schedule").verify.verify_trigger_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    triggerName="[string]Trigger name",
    verifyType="[string]Type of verification",
    elapsedMinutes="[int]Elapsed time (minutes)",
    timeOffsetToken="[string]Time offset token",
})

Gs2Schedule:VerifyEventByUserId

Verify whether the Event is active by User ID

Verifies whether the specified event is currently in its active schedule period for the specified user. The verifyType can be set to inSchedule or notInSchedule. Returns an error if the verification condition is not met.

Quantity specification supported: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
eventNamestring
~ 128 charsEvent name
Unique Event name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
verifyTypestring (enum)
enum {
  “inSchedule”,
  “notInSchedule”
}
Type of verification
DefinitionDescription
inScheduleThe event is in its active period
notInScheduleThe event is not in its active period
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Schedule:VerifyEventByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "eventName": "[string]Event name",
        "verifyType": "[string]Type of verification",
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Schedule:VerifyEventByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  eventName: "[string]Event name"
  verifyType: "[string]Type of verification"
  timeOffsetToken: "[string]Time offset token"
transaction.service("schedule").verify.verify_event_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    eventName="[string]Event name",
    verifyType="[string]Type of verification",
    timeOffsetToken="[string]Time offset token",
})

Consume Action

Gs2Schedule:DeleteTriggerByUserId

Delete Trigger by User ID

Deletes the specified trigger for the specified user. Deleting a trigger deactivates associated relative schedule events.

Quantity specification supported: NO

Reversible action: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
triggerNamestring
~ 128 charsTrigger name
Unique Trigger name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Schedule:DeleteTriggerByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "triggerName": "[string]Trigger name",
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Schedule:DeleteTriggerByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  triggerName: "[string]Trigger name"
  timeOffsetToken: "[string]Time offset token"
transaction.service("schedule").consume.delete_trigger_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    triggerName="[string]Trigger name",
    timeOffsetToken="[string]Time offset token",
})

Acquire Action

Gs2Schedule:TriggerByUserId

Execute the Trigger by User ID

Pulls a trigger for the specified user. The trigger strategy determines behavior: renew resets with new TTL, extend extends existing TTL, drop ignores if already pulled, repeatCycleEnd/repeatCycleNextStart/absoluteEnd aligns expiration with the specified event’s schedule. Pulling a trigger activates associated relative schedule events.

Quantity specification supported: NO

Reversible action: YES

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
triggerNamestring
~ 128 charsTrigger name
Unique Trigger name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
triggerStrategystring (enum)
enum {
  “renew”,
  “extend”,
  “drop”,
  “repeatCycleEnd”,
  “repeatCycleNextStart”,
  “absoluteEnd”
}
Trigger Execution Policy
DefinitionDescription
renewRedraw with a new period if the trigger has already been pulled
extendExtend the period if the trigger has already been pulled
dropIgnore if the trigger has already been pulled
repeatCycleEndTrigger to expire at the end of the repeat period of the specified event
repeatCycleNextStartTrigger to expire at the next repeat start date and time of the specified event
absoluteEndTrigger to expire at the end date and time of the specified event
ttlint{triggerStrategy} in [“renew”, “extend”, “drop”]
✓*
0 ~ 2147483646Trigger expiration time (seconds)
* Required if triggerStrategy is “renew”,“extend”,“drop”
eventIdstring{triggerStrategy} in [“repeatCycleEnd”, “repeatCycleNextStart”, “absoluteEnd”]
✓*
~ 1024 charsEvent GRN
* Required if triggerStrategy is “repeatCycleEnd”,“repeatCycleNextStart”,“absoluteEnd”
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Schedule:TriggerByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "triggerName": "[string]Trigger name",
        "userId": "[string]User ID",
        "triggerStrategy": "[string]Trigger Execution Policy",
        "ttl": "[int]Trigger expiration time (seconds)",
        "eventId": "[string]Event GRN",
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Schedule:TriggerByUserId
request:
  namespaceName: "[string]Namespace name"
  triggerName: "[string]Trigger name"
  userId: "[string]User ID"
  triggerStrategy: "[string]Trigger Execution Policy"
  ttl: "[int]Trigger expiration time (seconds)"
  eventId: "[string]Event GRN"
  timeOffsetToken: "[string]Time offset token"
transaction.service("schedule").acquire.trigger_by_user_id({
    namespaceName="[string]Namespace name",
    triggerName="[string]Trigger name",
    userId="[string]User ID",
    triggerStrategy="[string]Trigger Execution Policy",
    ttl="[int]Trigger expiration time (seconds)",
    eventId="[string]Event GRN",
    timeOffsetToken="[string]Time offset token",
})

Gs2Schedule:ExtendTriggerByUserId

Extend the period of a trigger by User ID

Extends the expiration period of an existing trigger for the specified user by the specified number of seconds. If the trigger does not exist, a new trigger is created with the specified extension period as its TTL.

Quantity specification supported: YES

Reversible action: NO

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
triggerNamestring
~ 128 charsTrigger name
Unique Trigger name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
extendSecondsint
0 ~ 2147483646Trigger extension period (seconds)
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2Schedule:ExtendTriggerByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "triggerName": "[string]Trigger name",
        "userId": "[string]User ID",
        "extendSeconds": "[int]Trigger extension period (seconds)",
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2Schedule:ExtendTriggerByUserId
request:
  namespaceName: "[string]Namespace name"
  triggerName: "[string]Trigger name"
  userId: "[string]User ID"
  extendSeconds: "[int]Trigger extension period (seconds)"
  timeOffsetToken: "[string]Time offset token"
transaction.service("schedule").acquire.extend_trigger_by_user_id({
    namespaceName="[string]Namespace name",
    triggerName="[string]Trigger name",
    userId="[string]User ID",
    extendSeconds="[int]Trigger extension period (seconds)",
    timeOffsetToken="[string]Time offset token",
})