Documentation index for AI agents

GS2-JobQueue

비동기 잡 큐

GS2-JobQueue는 게임 서버에서 실행하는 처리를 비동기적으로 쌓아두기 위한 잡 큐 기능을 제공합니다.

게임 처리 중에는 즉시 결과를 반환할 필요가 없는 것이나, 서버 측에서 시간을 들여 단계적으로 진행하고 싶은 것이 있습니다. 이러한 처리를 “잡"으로 큐에 등록해 두고, 이후 플레이어가 접속한 시점이나 명시적인 API 호출을 통해 실행할 수 있습니다.

주요 용도

  • GS2-Script를 비동기로 실행하기 위한 실행 기반
  • 장시간 처리를 세부 단계로 분할하여, 각 단계를 잡으로 등록해 순차적으로 처리
  • 로그인 중에 발생한 리워드 배포 등을 모아서 서버 측에서 트랜잭션 발행·실행
  • 다른 마이크로서비스의 완료 알림 핸들러로서, 후속 처리를 비동기로 수행
graph LR
  Producer["잡 등록원<br/>(다른 마이크로서비스 / GS2-Script)"] --> Queue["GS2-JobQueue"]
  Queue --> Run["플레이어가 Run을 실행<br/>또는 자동 실행"]
  Run --> Script["GS2-Script"]
  Script -- 성공 --> Result["JobResult로 기록"]
  Script -- 실패 --> Retry{"최대 시도 횟수<br/>도달?"}
  Retry -- No --> Queue
  Retry -- Yes --> DeadLetter["DeadLetterJob으로 보관"]

자동 실행 모드

네임스페이스 설정에서 enableAutoRun을 활성화하면, 각 마이크로서비스의 API 처리 마지막에 사용자의 큐에 쌓여 있는 잡을 자동으로 실행합니다. 플레이어가 앱을 조작하는 것만으로 서버 측에 쌓인 잡이 순차적으로 소화됩니다.

enableAutoRun을 비활성화하는 경우에는 클라이언트에서 명시적으로 Run API를 호출하여 잡을 실행해야 합니다.

잡 결과

잡의 실행 결과는 시도 횟수(tryNumber)마다 JobResult로 기록됩니다. JobResult에는 GS2-Script의 종료 코드·실행 로그·결과 페이로드 등이 포함되어 있어, 나중에 실행 이력을 확인할 수 있습니다.

알림 설정

네임스페이스 설정에서 runNotification·pushNotification을 구성해 두면, 잡이 실행되었을 때 또는 새로운 잡이 큐에 쌓였을 때 GS2-Gateway를 경유하여 클라이언트에 알림을 보낼 수 있습니다. 이 알림을 계기로 클라이언트 측에서 남은 정보를 다시 취득하는 등의 연계가 가능합니다.

트랜잭션 액션

GS2-JobQueue는 다른 마이크로서비스로부터 완료 알림의 수신처로 호출되는 경우가 많아, 트랜잭션 액션으로서 잡 등록을 제공하고 있습니다.

  • 입수 액션: 잡을 사용자의 큐에 등록

예를 들어 GS2-Mission의 완료 보상으로 GS2-JobQueue에 잡을 쌓아두고, 나중에 한꺼번에 GS2-Script를 실행하는 구성이 가능합니다.

마스터 데이터 관리

GS2-JobQueue는 마스터 데이터를 가지지 않습니다. 동작은 네임스페이스 설정에서만 제어합니다.

구현 예제

자신의 큐에 쌓인 잡 실행

enableAutoRun을 비활성화한 경우나, 명시적으로 잡 소화를 진행하고 싶은 경우에 호출합니다. Run을 호출하면 잡을 1건 꺼내어 GS2-Script를 실행하고, 그 결과를 반환합니다. IsLastJobtrue이면 더 이상 소화해야 할 잡이 남아있지 않음을 나타냅니다.

    var domain = gs2.JobQueue.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var result = await domain.RunAsync(
    );
    var isLastJob = domain.IsLastJob;
    var needRetry = result.NeedRetry;
    const auto Domain = Gs2->JobQueue->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto Future = Domain->Run(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto IsLastJob = Domain->IsLastJob;
    const auto NeedRetry = Future->GetTask().Result()->NeedRetry;
# SDK 레벨에서 실행되므로 명시적으로 API를 호출할 필요가 없습니다

잡 실행 결과 취득

특정 잡의 특정 시도 횟수에 대한 실행 결과를 취득합니다.

    var item = await gs2.JobQueue.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Job(
        jobName: "job-0001"
    ).JobResult(
        tryNumber: 1
    ).ModelAsync();
    const auto Domain = Gs2->JobQueue->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Job(
        "job-0001" // jobName
    )->JobResult(
        1 // tryNumber
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto Result = Future->GetTask().Result();
var domain = ez.job_queue.namespace_(
        "namespace-0001"
    ).me(game_session).job(
        "job-0001"
    ).job_result(
        null
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

잡 상태 취득

큐에 쌓인 잡의 최신 상태를 취득합니다. 잡의 현재 시도 횟수나 등록된 GS2-Script 정보 등을 확인할 수 있습니다.

    var item = await gs2.JobQueue.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Job(
        jobName: "job-0001"
    ).ModelAsync();
    const auto Future = Gs2->JobQueue->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Job(
        "job-0001" // jobName
    )->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto Result = Future->GetTask().Result();
var domain = ez.job_queue.namespace_(
    "namespace-0001"
).me(game_session).job("job-0001")
var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return
var item = async_result.result

상세 레퍼런스