내보내기 작업 만들기

이 페이지에서는 작업을 만들어 push 큐에 추가하는 방법에 대해 설명합니다. 태스크를 처리하려면 새 태스크 객체를 만들어 큐에 추가해야 합니다. 태스크를 처리하는 서비스와 핸들러를 명시적으로 지정하고 필요에 따라 태스크별 데이터를 핸들러에 함께 전달할 수 있습니다. 태스크를 실행할 시간을 예약하거나 태스크가 실패할 경우 재시도할 횟수를 제한하는 등 태스크의 구성을 세부적으로 조정할 수도 있습니다.

새 태스크 만들기

태스크를 만들어 큐에 추가하려면 QueueFactory를 사용하여 Queue를 가져오고 add() 메서드를 호출합니다. 팩토리의 getQueue() 메서드를 사용하여 queue.xml 파일에 지정된, 명명된 큐를 가져오거나 getDefaultQueue()를 사용하여 기본 큐를 가져올 수 있습니다. Queueadd() 메서드를 TaskOptions 인스턴스(TaskOptions.Builder에 의해 생성됨)와 함께 호출하거나 인수 없이 호출하여 큐의 기본 옵션으로 태스크를 만들 수 있습니다.

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
Queue queue = QueueFactory.getDefaultQueue();
queue.add(TaskOptions.Builder.withUrl("/worker").param("key", key));

작업자 서비스 지정

큐에서 태스크를 꺼내면 태스크 큐 서비스가 작업자 서비스로 해당 태스크를 전송합니다. 모든 태스크에는 최종적으로 태스크를 수행할 서비스와 핸들러를 결정하는 targeturl이 있습니다.

target

target은 태스크를 수행하기 위해 HTTP 요청을 수신할 서비스를 지정합니다. 서비스/버전/인스턴스를 표준 형식 중 하나로 지정하는 문자열로서 가장 일반적으로 사용되는 형식은 다음과 같습니다.

    service
    version.service
    instance.version.service

target 문자열은 앱의 도메인 이름 앞에 추가됩니다. 다음 세 가지 방법으로 태스크의 target을 설정할 수 있습니다.

  • 작업을 생성할 때 target을 선언합니다. 태스크 생성 시 TaskOptionsHost 헤더를 설정하여 명시적으로 target을 설정할 수 있습니다.

    taskOptions.header("Host", versionHostname)
    

  • queue-blue정의에서처럼 queue.xml에서 큐를 정의할 때 target 지시문을 포함합니다. target이 있는 큐에 추가되는 모든 태스크는 태스크 생성 시점에 다른 target이 할당되었더라도 큐의 target을 사용합니다.

  • 앞의 두 가지 방법 중 하나로 target을 지정하지 않으면 태스크를 큐에 추가한 서비스 버전이 태스크의 target이 됩니다. 기본 서비스와 버전에서 이 방식으로 태스크를 큐에 추가한 경우, 태스크가 실행되기 전에 기본 버전이 변경되면 새 기본 버전에서 태스크가 실행됩니다.

url

url은 target 서비스의 핸들러 중에서 태스크를 수행할 핸들러 하나를 선택합니다.

url은 target 서비스의 핸들러 URL 패턴 중 하나와 일치해야 합니다. 태스크에 지정된 메서드가 GET 또는 PULL인 경우 url에 쿼리 매개변수가 포함될 수 있습니다. url을 지정하지 않으면 기본 URL인 /_ah/queue/[QUEUE_NAME]이 사용되며, 여기서 [QUEUE_NAME]은 태스크의 큐 이름입니다.

핸들러에 데이터 전달

태스크에 지정된 메서드가 GET 또는 PULL인 경우에만 태스크의 URL에 포함되는 쿼리 매개변수로 데이터를 핸들러에 전달할 수 있습니다.

TaskOptions.Builder 생성자에는 데이터를 HTTP 요청의 페이로드로 추가하고 쿼리 매개변수로 URL에 추가되는 매개변수로 추가하는 메서드가 있습니다.

params
POST 메서드를 페이로드와 함께 사용하거나 GET 메서드를 사용 중이고 쿼리 매개변수에 url을 포함시킨 경우, params를 지정하지 마세요.

태스크 이름 지정

새 태스크를 만들면 기본적으로 App Engine이 태스크에 고유한 이름을 할당합니다. 그러나 name 매개변수를 사용하면 태스크 이름을 직접 할당할 수 있습니다. 태스크 이름을 직접 할당하면 명명된 태스크가 중복되지 않는다는 이점이 있습니다. 즉, 태스크 이름을 사용하면 한 태스크가 한 번만 추가됨을 보장할 수 있습니다. 중복 제거는 태스크 완료 또는 삭제 후 9일 동안 유지됩니다.

중복 제거 로직은 상당한 성능 오버헤드를 유발하며, 이에 따라 지연 시간이 증가하고 명명된 태스크와 관련하여 오류율이 상승할 수 있습니다. 태스크 이름이 타임스탬프처럼 순차적인 경우에는 이러한 비용이 대폭 증가할 수 있습니다. 따라서 이름을 직접 할당할 때는 태스크 이름에 콘텐츠의 해시와 같이 고르게 분산되는 프리픽스를 사용하는 것이 좋습니다.

태스크 이름을 직접 할당하는 경우 이름의 최대 길이는 500자이며 대문자, 소문자, 숫자, 밑줄, 하이픈을 포함할 수 있습니다.

비동기식으로 태스크 추가

기본적으로 큐에 태스크를 추가하는 호출은 동기식입니다. 대부분의 경우 동기 호출은 원활하게 작동합니다. 큐에 태스크를 추가하는 과정은 일반적으로 신속하게 이루어집니다. 태스크 추가에 매우 긴 시간이 드는 경우가 일부 있지만 태스크를 추가하는 데 걸리는 시간의 중앙값은 5ms 미만입니다.

여러 큐에 태스크를 추가하는 과정은 일괄 처리가 불가능하므로 Task Queue API는 이러한 태스크를 병렬로 추가하여 이 같은 지연 시간을 최소화하는 비동기 호출 기능도 제공합니다. 이 기능은 동시에 여러 큐에 여러 개의 태스크 작업을 추가해야 하고 지연 시간에 극도로 민감한 애플리케이션을 구축할 경우에 유용합니다.

태스크 큐에 비동기 호출을 수행하려면 Queue 클래스가 제공하는 비동기 메서드를 사용합니다. 그런 다음 반환된 Future에서 get를 호출하여 요청을 강제로 완료합니다. 트랜잭션에 태스크를 비동기식으로 추가할 경우, 트랜잭션을 커밋하기 전에 Future에서 get()을 호출하여 요청이 완료되었는지 확인해야 합니다.

Cloud Datastore 트랜잭션에서 큐에 태스크 추가

Datastore 트랜잭션의 일부로 큐에 태스크를 추가하면 트랜잭션이 성공적으로 커밋되는 경우에만 큐에 태스크가 추가됩니다. 트랜잭션에 추가된 태스크는 트랜잭션의 일부로 간주되며 동일한 수준의 격리 및 일관성이 적용됩니다.

애플리케이션은 단일 트랜잭션 도중 태스크 큐에 트랜잭션 태스크를 5개를 초과하여 삽입할 수 없습니다. 트랜잭션 태스크의 이름은 사용자가 지정한 이름이 아니어야 합니다.

다음 코드 샘플에서는 Datastore 트랜잭션의 일부로 push 큐에 트랜잭션 태스크를 삽입하는 방법을 보여줍니다.

DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Queue queue = QueueFactory.getDefaultQueue();
try {
    Transaction txn = ds.beginTransaction();

    // ...

    queue.add(TaskOptions.Builder.withUrl("/path/to/my/worker"));

    // ...
    txn.commit();
} catch (DatastoreFailureException e) {
}

작업자 서비스 대신 DeferredTask 사용

앞 섹션에서 설명한 것처럼 개별 작업마다 핸들러를 설정하거나 작업의 복잡한 인수를 직렬화 및 역직렬화하기는 번거로울 수 있으며, 대기열에서 종류가 다양한 소규모 작업을 많이 실행하려는 경우에는 특히 그러합니다. 자바 SDK에는 DeferredTask라는 인터페이스가 포함되어 있습니다. 이 인터페이스를 사용하면 단일 메서드로 태스크 하나를 정의할 수 있습니다. 이 인터페이스는 자바 직렬화를 사용하여 한 단위의 작업을 하나의 태스크 큐로 패키징합니다. 해당 메서드에서 간단한 결과가 반환되면 성공으로 간주합니다. 이러한 메서드에서 예외가 생성되면 실패로 간주합니다.


/** A hypothetical expensive operation we want to defer on a background task. */
public static class ExpensiveOperation implements DeferredTask {

  @Override
  public void run() {
    System.out.println("Doing an expensive operation...");
    // expensive operation to be backgrounded goes here
  }
}

/**
 * Basic demonstration of adding a deferred task.
 *
 * @param request servlet request
 * @param resp servlet response
 */
@Override
public void doGet(final HttpServletRequest request, final HttpServletResponse resp)
    throws IOException {
  // Add the task to the default queue.
  Queue queue = QueueFactory.getDefaultQueue();

  // Wait 5 seconds to run for demonstration purposes
  queue.add(
      TaskOptions.Builder.withPayload(new ExpensiveOperation())
          .etaMillis(System.currentTimeMillis() + DELAY_MS));

  resp.setContentType("text/plain");
  resp.getWriter().println("Task is backgrounded on queue!");
}

다중 테넌트 애플리케이션에서 작업 처리

기본적으로 push 큐에서는 태스크 생성 시 네임스페이스 관리자에 설정된 현재 네임스페이스를 사용합니다. 애플리케이션이 멀티테넌시 지원을 사용할 경우 Namespaces Java 8 API를 참조하세요.

다음 단계