GS2-Enhance 트랜잭션 액션
액션의 조합과 동시 실행
모든 서비스에 공통되는 전제는 트랜잭션 액션의 조합에 정리되어 있습니다. 먼저 그쪽을 읽어 주십시오. 이 절의 나머지는 GS2-Enhance 고유의 내용입니다.
GS2-Enhance의 트랜잭션 액션은 진행을 거치는 것과 거치지 않는 것 두 가지로 나뉩니다. 진행은 네임스페이스와 사용자의 조합으로 결정되며, 사용자당 하나만 존재합니다.
| 조작 | 같은 행을 겹쳤을 때 | 중첩 너머 | 다른 대상이 되는 경계 | 직렬 실행 모드 활성화 시 |
|---|---|---|---|---|
진행의 생성CreateProgressByUserId | 1건으로 통합된다 | 실패한다 | 네임스페이스·사용자 | 생성끼리의 충돌은 변하지 않고 계속 실패한다. 두 번째는 실제 중복을 막는 것과 같은 읽기로 첫 번째의 진행을 볼 수 있게 되어 “이미 존재한다"고 거부되기 때문이다. 두 번째에 force를 지정해도 해결되지 않는다. 이 경우 확인은 건너뛰지만, 같은 행에 대한 두 개의 쓰기를 하나로 묶을 수 없어 트랜잭션이 실패한다(400). 파기와의 충돌도 계속 실패한다(후술) |
진행의 파기DeleteProgressByUserId | 1건으로 통합된다 | 실패한다 | 네임스페이스·사용자 | 계속 실패한다. 1건으로 묶이지 않게 되므로, 두 번째 파기는 이미 사라진 진행에 대해 실행되어 찾을 수 없음(404)으로 거부된다 |
직접 강화·해방DirectEnhanceByUserId UnleashByUserId | 강화 레이트·대상·소재가 모두 같으면 1건으로 통합된다. 하나라도 다르면 각각 실행된다 | 진행을 건드리지 않는다 | 네임스페이스·사용자·강화 레이트·대상 아이템·소재 | 변하지 않는다. 진행을 건드리지 않는 것은 그대로다 |
생성과 파기는 행이 다르고 경계가 같습니다. 하나의 트랜잭션에 넣을 수는 없습니다.
진행의 생성은 이미 다른 진행이 있으면 실패합니다. 이로써 동시에 진행할 수 있는 강화가 하나로 유지됩니다. 이 판정은 트랜잭션 시작 시점의 상태에 대해 이루어지므로, 충돌 문제를 별개로 하더라도 진행을 파기한 뒤 새 진행을 만들 수는 없습니다.직렬 실행 모드(enableSequentialExecution 또는 TransactionSettingV2)를 활성화해도 이 흐름은 불가능합니다. 파기는 소비 액션으로 생성(획득 액션)보다 반드시 먼저 실행되므로 생성의 존재 확인 자체는 통과합니다. 그러나 파기와 생성은 같은 행에 대한 두 개의 쓰기가 되어, 이를 하나로 묶는 시점에 트랜잭션이 실패합니다(400). 진행을 파기한 뒤 새 진행을 만들려면 계속해서 트랜잭션을 두 개로 나누어야 합니다. 생성끼리를 함께 둔 경우의 동작도 변하지 않습니다(위 표 참조).
DirectEnhanceByUserId와 UnleashByUserId는 진행을 전혀 건드리지 않습니다. 무엇을 소비하고 무엇을 획득할지를 산출하여, 그것들을 자신의 트랜잭션으로 발행합니다. 소재가 다른 두 개는 다른 대상이므로 둘 다 실행되지만, 소비하는 것과 획득하는 것은 같은 트랜잭션에 모입니다.
강화의 소재는 GS2-Inventory에서 소비되고 결과도 GS2-Inventory에서 획득되는 것이 일반적입니다. 바깥쪽 트랜잭션이 같은 아이템을 건드리는 경우에는 GS2-Inventory의 페이지도 함께 확인해 주십시오.
중첩된 트랜잭션에 주의
안쪽에서 생성된 진행과 바깥쪽에서 파기된 진행이 충돌하여 트랜잭션이 실패합니다. 직렬 실행 모드를 활성화하면 이 실패는 일어나지 않습니다. 파기는 소비 액션이므로 안쪽의 생성을 일으키는 획득 액션보다 반드시 먼저 실행되고, 안쪽 생성의 존재 확인이 실행되는 시점에는 이미 파기가 끝나 방해되는 진행이 없는 상태가 됩니다.
제한을 회피하고 싶은 경우
진행의 생성, 직접 강화, 해방은 획득 액션, 진행의 파기는 소비 액션입니다. 생성끼리의 충돌은 acquireActionUseJobQueue를 활성화하면 해소할 수 있습니다. 생성과 파기의 공존은 enableAtomicCommit을 비활성화하면 해소되며, 이때 소비 액션이 획득 액션보다 먼저 실행되므로 파기한 뒤 새 진행을 만드는 흐름도 성립하게 됩니다.
동시 실행과 재시도
같은 사용자의 진행을 여러 요청이 동시에 생성·파기한 경우, 나중에 확정된 쪽이 충돌(409)이 됩니다. 재시도하면 최신 상태로 다시 판정되므로, 진행이 기대한 상태라면 성공하고 이미 다른 강화가 시작되었다면 오류가 반환됩니다.
직접 강화와 해방은 진행을 건드리지 않으므로, 어느 정도 충돌하는지는 소재와 결과가 속한 서비스에 달려 있습니다.
Consume Action
소비 액션
Gs2Enhance:DeleteProgressByUserId
사용자 ID를 지정하여 실행 중인 강화의 진행 정보를 삭제
지정된 사용자의 현재 진행 중인 강화의 진행 정보 레코드를 삭제합니다.
진행 중인 2단계 강화가 취소되며, 사전 계산된 경험치와 보너스 레이트는 폐기됩니다.
Start 단계에서 이미 소비된 소재는 자동으로 반환되지 않습니다.
수량 지정 가능한 액션: 아니오
반전 가능한 액션: 아니오
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||
| userId | string | ✓ | ~ 128자 | 사용자ID#{userId}로 설정하면 로그인 중인 사용자ID로 치환됩니다. | ||
| timeOffsetToken | string | ~ 1024자 | 타임 오프셋 토큰 |
{
"action": "Gs2Enhance:DeleteProgressByUserId",
"request": {
"namespaceName": "[string]네임스페이스 이름",
"userId": "[string]사용자ID",
"timeOffsetToken": "[string]타임 오프셋 토큰"
}
}action: Gs2Enhance:DeleteProgressByUserId
request:
namespaceName: "[string]네임스페이스 이름"
userId: "[string]사용자ID"
timeOffsetToken: "[string]타임 오프셋 토큰"transaction.service("enhance").consume.delete_progress_by_user_id({
namespaceName="[string]네임스페이스 이름",
userId="[string]사용자ID",
timeOffsetToken="[string]타임 오프셋 토큰",
})Acquire Action
입수 액션
Gs2Enhance:DirectEnhanceByUserId
사용자 ID를 지정하여 강화를 실행
강화 레이트 모델에 기반하여 지정된 소재를 소비해 대상 아이템 세트에 경험치를 부여합니다.
획득 경험치는 레이트 모델에서 정의된 경험치 계층에 따라 소재로부터 계산되며, 보너스 레이트는 설정된 보너스 레이트 확률 테이블에서 추첨됩니다.
결과에는 획득한 경험치량과 적용된 보너스 레이트가 포함됩니다.
소재의 소비와 경험치 획득을 실행하기 위한 트랜잭션이 발행됩니다.
수량 지정 가능한 액션: 아니오
반전 가능한 액션: 아니오
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||
| rateName | string | ✓ | ~ 128자 | 강화 레이트 모델 이름 강화 레이트 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(밑줄) .(마침표)로 지정합니다. | ||
| userId | string | ✓ | ~ 128자 | 사용자ID#{userId}로 설정하면 로그인 중인 사용자ID로 치환됩니다. | ||
| targetItemSetId | string | ✓ | ~ 1024자 | 강화 대상 아이템 세트의 GRN | ||
| materials | List<Material> | ✓ | 1 ~ 10 items | 강화 소재 목록 | ||
| config | List<Config> | [] | 0 ~ 32 items | 트랜잭션 변수에 적용할 설정값 | ||
| timeOffsetToken | string | ~ 1024자 | 타임 오프셋 토큰 |
{
"action": "Gs2Enhance:DirectEnhanceByUserId",
"request": {
"namespaceName": "[string]네임스페이스 이름",
"rateName": "[string]강화 레이트 모델 이름",
"userId": "[string]사용자ID",
"targetItemSetId": "[string]강화 대상 아이템 세트의 GRN",
"materials": [
{
"materialItemSetId": "[string]강화 소재가 되는 아이템 세트의 GRN",
"count": "[int]소비 수량"
}
],
"config": [
{
"key": "[string]이름",
"value": "[string]값"
}
],
"timeOffsetToken": "[string]타임 오프셋 토큰"
}
}action: Gs2Enhance:DirectEnhanceByUserId
request:
namespaceName: "[string]네임스페이스 이름"
rateName: "[string]강화 레이트 모델 이름"
userId: "[string]사용자ID"
targetItemSetId: "[string]강화 대상 아이템 세트의 GRN"
materials:
- materialItemSetId: "[string]강화 소재가 되는 아이템 세트의 GRN"
count: "[int]소비 수량"
config:
- key: "[string]이름"
value: "[string]값"
timeOffsetToken: "[string]타임 오프셋 토큰"transaction.service("enhance").acquire.direct_enhance_by_user_id({
namespaceName="[string]네임스페이스 이름",
rateName="[string]강화 레이트 모델 이름",
userId="[string]사용자ID",
targetItemSetId="[string]강화 대상 아이템 세트의 GRN",
materials={
{
materialItemSetId="[string]강화 소재가 되는 아이템 세트의 GRN",
count="[int]소비 수량"
}
},
config={
{
key="[string]이름",
value="[string]값"
}
},
timeOffsetToken="[string]타임 오프셋 토큰",
})Gs2Enhance:UnleashByUserId
사용자ID를 지정하여 한계돌파를 실행
GS2-Grade에서 관리하는 그레이드를 올리는 강화 처리에서 사용됩니다.
그중에서도 동일 종류의 아이템을 소재로 소비하여 레벨 상한을 올리는 유형의 한계돌파에 사용됩니다.
지정된 소재를 소비하는 대신 한계돌파 대상 리소스의 그레이드를 1 올릴 수 있습니다.
소재가 되는 리소스가 경험치 등의 리소스를 가지고 있더라도, 그 리소스는 계승되지 않습니다.
계승이 필요한 경우에는 사전에 다른 리소스로 계승하기 위한 리소스로 변환해 두어야 합니다.
수량 지정 가능한 액션: 아니오
반전 가능한 액션: 아니오
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||
| rateName | string | ✓ | ~ 128자 | 강화 레이트 모델 이름 강화 레이트 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(밑줄) .(마침표)로 지정합니다. | ||
| userId | string | ✓ | ~ 128자 | 사용자ID#{userId}로 설정하면 로그인 중인 사용자ID로 치환됩니다. | ||
| targetItemSetId | string | ✓ | ~ 1024자 | 한계돌파 대상 아이템 세트의 GRN | ||
| materials | List<string> | ✓ | 1 ~ 1000 items | 한계돌파 소재 목록 | ||
| config | List<Config> | [] | 0 ~ 32 items | 트랜잭션 변수에 적용할 설정값 | ||
| timeOffsetToken | string | ~ 1024자 | 타임 오프셋 토큰 |
{
"action": "Gs2Enhance:UnleashByUserId",
"request": {
"namespaceName": "[string]네임스페이스 이름",
"rateName": "[string]강화 레이트 모델 이름",
"userId": "[string]사용자ID",
"targetItemSetId": "[string]한계돌파 대상 아이템 세트의 GRN",
"materials": [
"[string]소재"
],
"config": [
{
"key": "[string]이름",
"value": "[string]값"
}
],
"timeOffsetToken": "[string]타임 오프셋 토큰"
}
}action: Gs2Enhance:UnleashByUserId
request:
namespaceName: "[string]네임스페이스 이름"
rateName: "[string]강화 레이트 모델 이름"
userId: "[string]사용자ID"
targetItemSetId: "[string]한계돌파 대상 아이템 세트의 GRN"
materials:
- "[string]소재"
config:
- key: "[string]이름"
value: "[string]값"
timeOffsetToken: "[string]타임 오프셋 토큰"transaction.service("enhance").acquire.unleash_by_user_id({
namespaceName="[string]네임스페이스 이름",
rateName="[string]강화 레이트 모델 이름",
userId="[string]사용자ID",
targetItemSetId="[string]한계돌파 대상 아이템 세트의 GRN",
materials={
"[string]소재"
},
config={
{
key="[string]이름",
value="[string]값"
}
},
timeOffsetToken="[string]타임 오프셋 토큰",
})Gs2Enhance:CreateProgressByUserId
사용자 ID를 지정하여 강화를 시작
2단계 강화 플로우를 위한 진행 정보 레코드를 작성합니다.
대상 아이템 세트와 소재를 레이트 모델에 대해 검증하고, 소재로부터 획득 경험치를 계산하며, 확률 테이블에서 보너스 레이트를 추첨합니다.
계산된 경험치와 보너스 레이트는 진행 정보 레코드에 저장되어 End API에서 강화 완료 시 사용됩니다.
force가 true인 경우, 사용자의 기존 진행 정보는 폐기되고 대체됩니다.
수량 지정 가능한 액션: 아니오
반전 가능한 액션: 예
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||
| userId | string | ✓ | ~ 128자 | 사용자ID#{userId}로 설정하면 로그인 중인 사용자ID로 치환됩니다. | ||
| rateName | string | ✓ | ~ 128자 | 강화 레이트 모델 이름 이 강화 조작의 파라미터를 정의하는 강화 레이트 모델의 이름입니다. 대상 인벤토리, 소재 인벤토리, 경험치 계층, 보너스 레이트를 지정하는 모델을 참조합니다. | ||
| targetItemSetId | string | ✓ | ~ 1024자 | 강화 대상 아이템 세트의 GRN | ||
| materials | List<Material> | 0 ~ 10 items | 강화 소재 목록 | |||
| force | bool | false | 이미 시작된 강화가 있는 경우 이를 폐기하고 시작할지 | |||
| timeOffsetToken | string | ~ 1024자 | 타임 오프셋 토큰 |
{
"action": "Gs2Enhance:CreateProgressByUserId",
"request": {
"namespaceName": "[string]네임스페이스 이름",
"userId": "[string]사용자ID",
"rateName": "[string]강화 레이트 모델 이름",
"targetItemSetId": "[string]강화 대상 아이템 세트의 GRN",
"materials": [
{
"materialItemSetId": "[string]강화 소재가 되는 아이템 세트의 GRN",
"count": "[int]소비 수량"
}
],
"force": "[bool]이미 시작된 강화가 있는 경우 이를 폐기하고 시작할지",
"timeOffsetToken": "[string]타임 오프셋 토큰"
}
}action: Gs2Enhance:CreateProgressByUserId
request:
namespaceName: "[string]네임스페이스 이름"
userId: "[string]사용자ID"
rateName: "[string]강화 레이트 모델 이름"
targetItemSetId: "[string]강화 대상 아이템 세트의 GRN"
materials:
- materialItemSetId: "[string]강화 소재가 되는 아이템 세트의 GRN"
count: "[int]소비 수량"
force: "[bool]이미 시작된 강화가 있는 경우 이를 폐기하고 시작할지"
timeOffsetToken: "[string]타임 오프셋 토큰"transaction.service("enhance").acquire.create_progress_by_user_id({
namespaceName="[string]네임스페이스 이름",
userId="[string]사용자ID",
rateName="[string]강화 레이트 모델 이름",
targetItemSetId="[string]강화 대상 아이템 세트의 GRN",
materials={
{
materialItemSetId="[string]강화 소재가 되는 아이템 세트의 GRN",
count="[int]소비 수량"
}
},
force="[bool]이미 시작된 강화가 있는 경우 이를 폐기하고 시작할지",
timeOffsetToken="[string]타임 오프셋 토큰",
})