Ejemplo de cola de tareas de Go

En este ejemplo se crea una aplicación que muestra un formulario HTML. Introduce una cadena en el cuadro de diálogo y haz clic en Add. La aplicación cuenta el número de veces que introduces cualquier cadena de esta forma.

La aplicación hace lo siguiente:

  • Cuando haces clic en Add, el formulario usa una solicitud HTTP POST para enviar la cadena a la aplicación que se está ejecutando en App Engine. Allí, la aplicación agrupa la cadena en una tarea y la envía a la cola predeterminada.
  • La cola reenvía la tarea a un controlador de tareas incluido, asignado a la URL /worker, que escribe la cadena de forma asíncrona en un almacén de datos.
  • Al enviar una solicitud HTTP GET, se muestra una lista de las cadenas que has introducido y el número de veces que has Add cada cadena, ya sea escribiéndola o haciendo clic en ella en el cuadro desplegable.

Para desplegar esta aplicación en App Engine, sigue estos pasos:

  1. Copia lo siguiente en un archivo llamado queue.yaml. De esta forma, la velocidad a la que se procesarán las tareas cambiará de 5 por segundo (valor predeterminado) 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 quieras (que termine 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. De esta forma, se 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 un proyecto de Google Cloud Platform con una aplicación de App Engine preparada y de haber inicializado y configurado el comando gcloud para ese proyecto.

  5. Usa el comando gcloud app deploy para desplegar la aplicación en App Engine.

  6. Para ver la aplicación en acción, usa el comando gcloud app browse.