Documentation index for AI agents

GS2-Quest 트랜잭션 액션

검증/소비/입수 각 트랜잭션 액션의 사양

액션의 조합과 동시 실행

모든 서비스에 공통되는 전제는 트랜잭션 액션의 조합에 정리되어 있습니다. 먼저 그쪽을 읽어 주십시오. 이 절의 나머지는 GS2-Quest 고유의 내용입니다.

GS2-Quest가 트랜잭션에 지정할 수 있는 액션은 2가지이며, 둘 다 네임스페이스와 사용자의 조합으로 결정되는 한 사용자의 진행을 대상으로 합니다. 진행은 사용자당 하나만 존재하며, 이것이 플레이어를 동시에 하나의 퀘스트로 제한하는 구조입니다.

조작같은 행을 겹쳤을 때중첩 너머다른 대상이 되는 경계
진행의 생성
CreateProgressByUserId
완전히 동일한 지정이라도 발행 시에 오류실패한다네임스페이스·사용자
진행의 파기
DeleteProgressByUserId
완전히 동일한 지정이라도 발행 시에 오류1건으로 통합된다네임스페이스·사용자

생성과 파기는 행이 다르고 경계가 같습니다. 진행의 유무와 관계없이 하나의 트랜잭션에 넣을 수는 없습니다. 발행 시에 오류가 됩니다.

진행의 생성은 이미 다른 진행이 있으면 실패합니다. 이 판정은 트랜잭션 시작 시점의 상태에 대해 이루어지므로, enableAtomicCommit이 활성화된 경우에는 충돌 문제를 별개로 하더라도 진행을 파기한 뒤 새 퀘스트를 시작하는 흐름을 하나의 트랜잭션으로 수행할 수는 없습니다. 트랜잭션을 나누어 주십시오.

진행은 사용자당 하나뿐이므로, 같은 사용자에 대한 생성을 하나의 트랜잭션에 두 개 나열하는 것 자체가 모순된 지시입니다. 어느 쪽을 실행해야 할지 판단할 근거가 없으므로, questModelIdforce도 설정도 완전히 같더라도 발행 시에 오류가 됩니다. 「한꺼번에 3개를 사서 퀘스트를 3번 시작한다」와 같은 지시는 표현할 수 없다고 생각해 주십시오. 파기끼리도 마찬가지로, 몇 건을 나열하더라도 발행 시에 오류가 됩니다.

퀘스트의 보상은 별도로 발행됩니다

퀘스트의 완료나 실패는 트랜잭션 액션이 아닙니다. 퀘스트가 종료되면 GS2-Quest가 그 보상을 자신의 트랜잭션으로 발행합니다. 그 때문에 보상이 속한 서비스의 제한이 그대로 해당되며, 아래의 내용도 해당됩니다.

이 트랜잭션에는 진행의 파기가 반드시 포함됩니다. 따라서 enableAtomicCommit이 활성화된 경우, 보상에 같은 네임스페이스의 CreateProgressByUserId를 두어 다음 퀘스트를 자동으로 시작할 수는 없습니다. 생성이 하나뿐이더라도 파기와의 공존이 되므로 발행 시에 오류가 됩니다. 퀘스트를 연쇄시키려면 트랜잭션을 나누어 주십시오.

중첩된 트랜잭션에 주의

안쪽에서 생성된 진행과 바깥쪽에서 파기된 진행이 충돌하여 트랜잭션이 실패합니다. 생성끼리도 같은 진행을 이중으로 기록하므로 실패합니다. 진행의 생성은 매번 다른 식별자와 난수 시드를 기록하기 때문에, 지정이 완전히 같더라도 기록하는 값은 일치하지 않으며, 값이 일치했을 때의 통합에는 해당하지 않습니다. 파기끼리만은 같은 진행의 삭제가 멱등이므로, 중첩 너머에서도 1회로 합쳐지며 실패하지 않습니다.

제한을 회피하고 싶은 경우

진행의 생성은 획득 액션, 파기는 소비 액션입니다. 생성끼리·파기끼리의 중복은 검사가 트랜잭션 발행 시, 설정이 적용되기 전에 실행되므로 acquireActionUseJobQueue를 활성화해도 enableAtomicCommit을 비활성화해도 해소되지 않습니다. 지정을 하나로 줄이거나 트랜잭션을 나누어 주십시오.

생성과 파기의 공존은 enableAtomicCommit을 비활성화하면 해소됩니다. 이때 소비 액션이 획득 액션보다 먼저 실행되므로, 파기한 뒤 새 퀘스트를 시작하는 흐름도 성립하게 됩니다. acquireActionUseJobQueue는 획득 액션끼리를 분리하는 설정이므로 공존의 해소에는 의지하지 마십시오. 획득 액션이 하나뿐일 때는 잡 큐에 쌓이지 않고 파기와 같은 트랜잭션에 남습니다.

동시 실행과 재시도

같은 사용자의 진행을 여러 요청이 동시에 생성·파기한 경우, 나중에 확정된 쪽이 충돌(409)이 됩니다. 재시도하면 최신 상태로 다시 판정되므로, 진행이 기대한 상태라면 성공하고 이미 다른 퀘스트가 시작되었다면 오류가 반환됩니다.


Consume Action

소비 액션

Gs2Quest:DeleteProgressByUserId

사용자 ID를 지정하여 퀘스트 진행 상황 삭제

지정한 사용자의 현재 퀘스트 진행 상황을 삭제합니다. 진행 중인 퀘스트를 취소하고 새로운 퀘스트를 시작할 수 있게 합니다.

수량 지정 가능한 액션: 아니오

반전 가능한 액션: 아니오

타입활성화 조건필수기본값값 제한설명
namespaceNamestring
~ 128자네임스페이스 이름
네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.
userIdstring
~ 128자사용자ID
#{userId}로 설정하면 로그인 중인 사용자ID로 치환됩니다.
timeOffsetTokenstring~ 1024자타임 오프셋 토큰
{
    "action": "Gs2Quest:DeleteProgressByUserId",
    "request": {
        "namespaceName": "[string]네임스페이스 이름",
        "userId": "[string]사용자ID",
        "timeOffsetToken": "[string]타임 오프셋 토큰"
    }
}
action: Gs2Quest:DeleteProgressByUserId
request:
  namespaceName: "[string]네임스페이스 이름"
  userId: "[string]사용자ID"
  timeOffsetToken: "[string]타임 오프셋 토큰"
transaction.service("quest").consume.delete_progress_by_user_id({
    namespaceName="[string]네임스페이스 이름",
    userId="[string]사용자ID",
    timeOffsetToken="[string]타임 오프셋 토큰",
})

Acquire Action

입수 액션

Gs2Quest:CreateProgressByUserId

사용자 ID를 지정하여 퀘스트 진행 상황 생성

퀘스트 모델을 참조하여 퀘스트 콘텐츠 추첨을 수행하고 퀘스트를 시작합니다. 이미 진행 중인 퀘스트가 있는 경우, force 플래그가 설정되어 있지 않으면 오류를 반환합니다.

수량 지정 가능한 액션: 아니오

반전 가능한 액션: 예

타입활성화 조건필수기본값값 제한설명
namespaceNamestring
~ 128자네임스페이스 이름
네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.
userIdstring
~ 128자사용자ID
#{userId}로 설정하면 로그인 중인 사용자ID로 치환됩니다.
questModelIdstring
~ 1024자시작할 퀘스트 모델 GRN
forceboolfalse이미 시작한 퀘스트가 있는 경우 이를 파기하고 시작할지 여부
configList<Config>[]0 ~ 32 items트랜잭션 변수에 적용할 설정값
timeOffsetTokenstring~ 1024자타임 오프셋 토큰
{
    "action": "Gs2Quest:CreateProgressByUserId",
    "request": {
        "namespaceName": "[string]네임스페이스 이름",
        "userId": "[string]사용자ID",
        "questModelId": "[string]시작할 퀘스트 모델 GRN",
        "force": "[bool]이미 시작한 퀘스트가 있는 경우 이를 파기하고 시작할지 여부",
        "config": [
            {
                "key": "[string]이름",
                "value": "[string]값"
            }
        ],
        "timeOffsetToken": "[string]타임 오프셋 토큰"
    }
}
action: Gs2Quest:CreateProgressByUserId
request:
  namespaceName: "[string]네임스페이스 이름"
  userId: "[string]사용자ID"
  questModelId: "[string]시작할 퀘스트 모델 GRN"
  force: "[bool]이미 시작한 퀘스트가 있는 경우 이를 파기하고 시작할지 여부"
  config: 
    - key: "[string]이름"
      value: "[string]값"
  timeOffsetToken: "[string]타임 오프셋 토큰"
transaction.service("quest").acquire.create_progress_by_user_id({
    namespaceName="[string]네임스페이스 이름",
    userId="[string]사용자ID",
    questModelId="[string]시작할 퀘스트 모델 GRN",
    force="[bool]이미 시작한 퀘스트가 있는 경우 이를 파기하고 시작할지 여부",
    config={
        {
            key="[string]이름",
            value="[string]값"
        }
    },
    timeOffsetToken="[string]타임 오프셋 토큰",
})