Criar tarefas push

Nesta página, descrevemos como criar tarefas e colocá-las em filas push. Quando quiser processar uma tarefa, você precisará criar um novo objeto de tarefa e colocá-lo em uma fila. É possível especificar explicitamente o serviço e o gerenciador que processam a tarefa e, como opção, passar dados específicos da tarefa para o gerenciador. Também é possível ajustar a configuração da tarefa, como agendá-la caso ela precise ser executada posteriormente ou limitar o número de vezes que a tarefa será repetida se falhar.

Como criar uma nova tarefa

Para criar e enfileirar uma tarefa, chame a função taskqueue.Add.

import("google.golang.org/appengine/taskqueue")

Como especificar o service worker

Quando uma tarefa é retirada da fila, o serviço de fila de tarefas a envia para um serviço de worker. Cada tarefa tem um destino e um url, que determinam o serviço e o gerenciador que realizarão a tarefa.

target

O destino especifica o serviço que receberá a solicitação HTTP para executar a tarefa. É uma string que especifica um serviço/versão/instância em qualquer uma das formas canônicas. As formas mais usadas são estas:

    service
    version.service
    instance.version.service

A string de destino precede o nome de domínio do aplicativo. Há três maneiras de definir o destino de uma tarefa:

  • Declarar o destino ao construir a tarefa. Para definir o destino explicitamente ao criar o objeto Task, configure o cabeçalho Host:

    h := http.Header{}
    h.Add("Host", "versionHostname")
    task := taskqueue.Task{
    	Header: h,
    }

  • Incluir uma diretiva target ao definir uma fila em queue.yaml, como na definição de queue-blue. Todas as tarefas incluídas em uma fila com um target terão esse destino, mesmo que outro destino seja atribuído à tarefa no momento da criação.

  • Se nenhum destino for especificado de acordo com um dos dois métodos anteriores, o destino da tarefa será a versão do serviço que a põe em fila. Se você colocar em fila uma tarefa do serviço e versão padrões dessa maneira, e a versão padrão mudar antes da execução da tarefa, esta será executada na nova versão padrão.

url

Com url, um dos gerenciadores no serviço de destino é selecionado para a execução da tarefa.

O url precisa corresponder a um dos padrões de URL do gerenciador no serviço de destino. O url poderá incluir parâmetros de consulta se o método especificado na tarefa for GET ou PULL. Se nenhum url for especificado, será usado o URL /_ah/queue/[QUEUE_NAME] padrão, em que [QUEUE_NAME] corresponde ao nome da fila da tarefa.

Como passar dados ao gerenciador

É possível passar dados como parâmetros de consulta ao gerenciador no URL da tarefa, mas somente se o método especificado na tarefa for GET ou PULL.

A função NewPOSTTask tem um argumento posicional para query_data. Os dados geralmente são um dicionário de pares chave-valor. Se o método da tarefa for POST ou PUT, os dados serão adicionados ao payload da solicitação HTTP. Se o método for GET, ele será adicionado ao URL como parâmetros de consulta.

Como nomear uma tarefa

Quando você cria uma nova tarefa, o App Engine atribui a ela um nome exclusivo por padrão. Porém, é possível atribuir à tarefa um nome de sua escolha usando o parâmetro name. Uma vantagem de escolher os nomes que serão atribuídos às tarefas é a remoção de duplicações, o que significa que é possível usar os nomes de tarefas para garantir que a tarefa seja adicionada apenas uma vez. A remoção de duplicações continua por nove dias após a conclusão ou exclusão da tarefa.

Observe que essa lógica de remoção de duplicações apresenta uma sobrecarga de desempenho significativa, resultando em maiores latências e taxas de erro potencialmente maiores associadas a tarefas nomeadas. Esses custos poderão aumentar significativamente se os nomes das tarefas forem sequenciais, como no caso de carimbos de data/hora. Então, se você mesmo atribuir os nomes, recomendamos usar um prefixo bem distribuído para nomes de tarefas, como um hash do conteúdo.

Se você atribuir seus próprios nomes às tarefas, observe que o comprimento máximo do nome é de 500 caracteres e o nome pode conter letras maiúsculas e minúsculas, números, sublinhados e hífens.

Como enfileirar tarefas em transações do Cloud Datastore

É possível enfileirar uma tarefa como parte de uma transação do Datastore, de modo que ela seja enfileirada e garantida para ser enfileirada apenas se a transação for confirmada. As tarefas adicionadas a uma transação são consideradas parte dela e têm o mesmo nível de isolamento e consistência.

Um aplicativo não pode inserir mais de cinco tarefas transacionais a filas de tarefas durante uma única transação. Tarefas transacionais não podem ter nomes especificados pelo usuário.

O exemplo de código a seguir demonstra como inserir tarefas transacionais em uma fila push como parte de uma transação do Datastore:

import (
	"net/url"

	"golang.org/x/net/context"

	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/taskqueue"
)

func f(ctx context.Context) {
	err := datastore.RunInTransaction(ctx, func(ctx context.Context) error {
		t := taskqueue.NewPOSTTask("/worker", url.Values{
			// ...
		})
		// Use the transaction's context when invoking taskqueue.Add.
		_, err := taskqueue.Add(ctx, t, "")
		if err != nil {
			// Handle error
		}
		// ...
		return nil
	}, nil)
	if err != nil {
		// Handle error
	}
	// ...
}

Como usar o pacote atrasado em vez de um serviço de worker

A configuração de um gerenciador para cada tarefa distinta (conforme descrito nas seções anteriores) pode ser complicada. A serialização e desserialização de argumentos complexos para a tarefa também podem ter complicações, especialmente se houver muitas tarefas diversas, porém pequenas, que você queira executar na fila. O SDK do Go inclui um pacote (appengine/delay) que expõe uma API simples, permitindo que você evite todo o trabalho de configuração de gerenciadores de tarefas dedicados, bem como de serialização e desserialização de seus parâmetros.

Para usar o pacote delay:

var expensiveFunc = delay.Func("some-arbitrary-key", func(ctx context.Context, a string, b int) {
	// do something expensive!
})

// Somewhere else
expensiveFunc.Call(ctx, "Hello, world!", 42)

O pacote delay serializa sua chamada de função e os respectivos argumentos. Depois, ele a adiciona à fila de tarefas. Quando a tarefa é executada, o pacote delay executa a função.

Saiba mais sobre como usar o pacote delay na documentação dele.

Como trabalhar com tarefas em um aplicativo multilocatário

Por padrão, as filas push usam o namespace atual configurado no gerenciador de namespace no momento da criação da tarefa. Se o aplicativo usar multilocação, veja a API Namespaces Go 1.11.

A seguir