Un ejemplo de lista de tareas en cola de Go

En este ejemplo, se crea una app que muestra un formulario HTML. Debes ingresar una string en el cuadro de diálogo y hacer clic en Add. La app cuenta la cantidad de veces que ingresas una string de esta forma.

La app hace lo siguiente:

  • Cuando haces clic en Add, el formulario usa una solicitud HTTP POST para enviar la string a la app que se ejecuta en App Engine. Allí, la app agrupa la string en una tarea y la envía a una cola predeterminada.
  • La cola reenvía la tarea a un controlador de tareas incluido, mapeado a la URL /worker, que escribe la string de forma asíncrona en un almacén de datos.
  • Si envías una solicitud HTTP GET, se muestra una lista de las strings que ingresaste y la cantidad de veces que hiciste Add en cada string. Puedes hacer esto si la escribes o si haces clic en ella en el menú desplegable.

Para implementar esta aplicación en App Engine, haz lo siguiente:

  1. Copia lo siguiente en un archivo llamado queue.yaml. Esto cambia la velocidad a la que se procesan las tareas de 5 por segundo (la configuración predeterminada) a 3 por segundo.

    queue:
    - name: default
      rate: 3/s
    
  2. En el mismo directorio, copia lo siguiente en un archivo con el nombre que desees (debe terminar en .go). Este es el código de la aplicación, incluido el controlador de tareas.

    
    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. En el mismo directorio, copia lo siguiente en un archivo llamado app.yaml. Esto configura tu aplicación para App Engine:

    runtime: go
    api_version: go1
    
    handlers:
    - url: /worker/.*
      script: _go_app
      login: admin
    - url: /.*
      script: _go_app
  4. Asegúrate de tener preparado un proyecto de Google Cloud Platform con una app de App Engine y de que inicializaste y configuraste el comando de gcloud para ese proyecto.

  5. Usa el comando gcloud app deploy para implementar la app en App Engine.

  6. Puedes ver la app en acción mediante el comando gcloud app browse.