Go 태스크 큐 예

이 예시에서는 HTML 양식을 표시하는 앱을 만듭니다. 대화상자에 문자열을 입력하고 Add를 클릭합니다. 앱에서는 이 방식으로 문자열이 입력되는 횟수를 계산합니다.

앱은 다음을 수행합니다.

  • Add를 클릭하면 양식에서 HTTP POST 요청을 사용하여 App Engine에서 실행 중인 앱에 문자열을 보냅니다. 이때 앱은 문자열을 번들로 묶어 태스크에 추가한 다음 기본 큐로 보냅니다.
  • 큐에서 URL /worker에 매핑된 포함 태스크 핸들러로 이 태스크를 전달하여 문자열을 비동기적으로 Datastore에 씁니다.
  • HTTP GET 요청을 보내면 입력한 문자열 목록과 각 문자열을 직접 입력하거나 드롭다운 상자에서 클릭하여 Add한 횟수가 표시됩니다.

이 앱을 App Engine에 배포하려면 다음 안내를 따르세요.

  1. 다음을 queue.yaml 파일에 복사합니다. 이렇게 하면 태스크가 처리되는 속도가 기본값인 초당 5회에서 초당 3회로 변경됩니다.

    queue:
    - name: default
      rate: 3/s
    
  2. 같은 디렉터리에서 다음 내용을 원하는 대로 이름을 지정한 파일(.go로 끝나는 이름)에 복사합니다. 태스크 핸들러를 포함한 애플리케이션 코드입니다.

    
    package counter
    
    import (
    	"html/template"
    	"net/http"
    
    	"google.golang.org/appengine"
    	"google.golang.org/appengine/datastore"
    	"google.golang.org/appengine/log"
    	"google.golang.org/appengine/taskqueue"
    )
    
    func init() {
    	http.HandleFunc("/", handler)
    	http.HandleFunc("/worker", worker)
    }
    
    type Counter struct {
    	Name  string
    	Count int
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	ctx := appengine.NewContext(r)
    	if name := r.FormValue("name"); name != "" {
    		t := taskqueue.NewPOSTTask("/worker", map[string][]string{"name": {name}})
    		if _, err := taskqueue.Add(ctx, t, ""); err != nil {
    			http.Error(w, err.Error(), http.StatusInternalServerError)
    			return
    		}
    	}
    	q := datastore.NewQuery("Counter")
    	var counters []Counter
    	if _, err := q.GetAll(ctx, &counters); err != nil {
    		http.Error(w, err.Error(), http.StatusInternalServerError)
    		return
    	}
    	if err := handlerTemplate.Execute(w, counters); err != nil {
    		http.Error(w, err.Error(), http.StatusInternalServerError)
    		return
    	}
    	// OK
    }
    
    func worker(w http.ResponseWriter, r *http.Request) {
    	ctx := appengine.NewContext(r)
    	name := r.FormValue("name")
    	key := datastore.NewKey(ctx, "Counter", name, 0, nil)
    	var counter Counter
    	if err := datastore.Get(ctx, key, &counter); err == datastore.ErrNoSuchEntity {
    		counter.Name = name
    	} else if err != nil {
    		log.Errorf(ctx, "%v", err)
    		return
    	}
    	counter.Count++
    	if _, err := datastore.Put(ctx, key, &counter); err != nil {
    		log.Errorf(ctx, "%v", err)
    	}
    }
    
    var handlerTemplate = template.Must(template.New("handler").Parse(handlerHTML))
    
    const handlerHTML = `
    {{range .}}
    <p>{{.Name}}: {{.Count}}</p>
    {{end}}
    <p>Start a new counter:</p>
    <form action="/" method="POST">
    <input type="text" name="name">
    <input type="submit" value="Add">
    </form>
    `
    
  3. 같은 디렉터리에서 다음을 app.yaml 파일에 복사합니다. 이렇게 하면 App Engine용 애플리케이션이 구성됩니다.

    runtime: go
    api_version: go1
    
    handlers:
    - url: /worker/.*
      script: _go_app
      login: admin
    - url: /.*
      script: _go_app
  4. Google Cloud Platform 프로젝트에 App Engine 앱이 준비되었으며 초기화하고 프로젝트에 gcloud 명령어를 구성했는지 확인합니다.

  5. gcloud app deploy 명령어를 사용하여 App Engine에 앱을 배포합니다.

  6. gcloud app browse 명령어를 사용하여 실행 중인 앱을 확인합니다.