Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O pacote do Azure Core (azcore
) no SDK do Azure para Go implementa vários padrões aplicados em todo o SDK:
- O fluxo de pipeline HTTP, que é o mecanismo HTTP subjacente usado pelas bibliotecas de cliente do SDK.
- Paginação (métodos que retornam coleções).
- Operações de execução prolongada (LROs).
Paginação (métodos que retornam coleções)
Muitos serviços do Azure retornam coleções de itens. Como o número de itens pode ser grande, esses métodos cliente retornam um Pager, o que permite que seu aplicativo processe uma página de resultados de cada vez. Esses tipos são definidos individualmente para vários contextos, mas compartilham características comuns, como um NextPage
método.
Por exemplo, suponha que haja um ListWidgets
método que retorna um WidgetPager
. Em seguida, você usaria o WidgetPager
conforme mostrado aqui:
func (c *WidgetClient) ListWidgets(options *ListWidgetOptions) WidgetPager {
// ...
}
pager := client.ListWidgets(options)
for pager.NextPage(ctx) {
for _, w := range pager.PageResponse().Widgets {
process(w)
}
}
if pager.Err() != nil {
// Handle error...
}
Operações de longa duração
Algumas operações no Azure podem levar muito tempo para serem concluídas, em qualquer lugar, de alguns segundos a alguns dias. Exemplos dessas operações incluem copiar dados de uma URL de origem para um blob de armazenamento ou treinar um modelo de IA para reconhecer formulários. Essas LROs (operações de execução longa) são inadequadas para o fluxo HTTP padrão de uma solicitação e resposta relativamente rápidas.
Por convenção, os métodos que iniciam um LRO são prefixados com "Begin" e retornam um Poller. O Poller é usado para sondar periodicamente o serviço até que a operação seja concluída.
Os exemplos a seguir ilustram vários padrões para lidar com LROs. Você também pode saber mais com o código-fonte poller.go no SDK.
Bloquear chamada para PollUntilDone
PollUntilDone
gerencia todo o intervalo de uma operação de sondagem até que um estado terminal seja atingido. Em seguida, retorna a resposta HTTP final para a operação de polling com o conteúdo do payload na interface respType
.
resp, err := client.BeginCreate(context.Background(), "blue_widget", nil)
if err != nil {
// Handle error...
}
w, err = resp.PollUntilDone(context.Background(), nil)
if err != nil {
// Handle error...
}
process(w)
Loop de pesquisa personalizado
Poll
envia uma solicitação de sondagem para o endpoint de sondagem e retorna a resposta ou um erro.
resp, err := client.BeginCreate(context.Background(), "green_widget")
if err != nil {
// Handle error...
}
poller := resp.Poller
for {
resp, err := poller.Poll(context.Background())
if err != nil {
// Handle error...
}
if poller.Done() {
break
}
// Do other work while waiting.
}
w, err := poller.FinalResponse(ctx)
if err != nil {
// Handle error...
}
process(w)
Retomar uma operação anterior
Extraia e salve o token de retomada de um Poller existente.
Para retomar a sondagem, talvez em outro processo ou em outro computador, crie uma nova PollerResponse
instância e, em seguida, inicialize-a chamando seu Resume
método, passando-o o token de retomada salvo anteriormente.
poller := resp.Poller
tk, err := poller.ResumeToken()
if err != nil {
// Handle error...
}
resp = WidgetPollerResponse()
// Resume takes the resume token as an argument.
err := resp.Resume(tk, ...)
if err != nil {
// Handle error...
}
for {
resp, err := poller.Poll(context.Background())
if err != nil {
// Handle error...
}
if poller.Done() {
break
}
// Do other work while waiting.
}
w, err := poller.FinalResponse(ctx)
if err != nil {
// Handle error...
}
process(w)
Fluxo de pipeline HTTP
Os vários clientes do SDK fornecem uma abstração sobre a API REST do Azure para habilitar a conclusão do código e a segurança do tipo de tempo de compilação para que você não precise lidar com a mecânica de transporte de nível inferior por HTTP. No entanto, você pode personalizar a mecânica de transporte (como repetições e registro em log).
O SDK faz solicitações HTTP por meio de um pipeline HTTP. O pipeline descreve a sequência de etapas executadas para cada ciclo completo de solicitação e resposta HTTP.
O pipeline é composto por um transporte junto com qualquer número de políticas:
- O transporte envia a solicitação para o serviço e recebe a resposta.
- Cada política conclui uma ação específica no fluxo de trabalho.
O diagrama a seguir ilustra o fluxo de um pipeline:
Todos os pacotes de cliente compartilham um pacote Core chamado azcore
. Esse pacote constrói o pipeline HTTP com seu conjunto ordenado de políticas, garantindo que todos os pacotes cliente se comportem de forma consistente.
Quando uma solicitação HTTP é enviada, todas as políticas são executadas na ordem em que foram adicionadas ao pipeline antes que a solicitação seja enviada ao ponto de extremidade HTTP. Essas políticas normalmente adicionam cabeçalhos de solicitação ou registram a solicitação HTTP de saída.
Depois que o serviço do Azure responder, todas as políticas são executadas na ordem inversa antes que a resposta seja enviada ao seu código. A maioria das políticas ignora a resposta, mas a política de registro registra a resposta. A política de repetição pode reemissar a solicitação, tornando seu aplicativo mais resiliente a falhas de rede.
Cada política é fornecida com os dados de solicitação ou resposta necessários, juntamente com qualquer contexto necessário para executar a política. A política conclui sua operação com os dados especificados e passa o controle para a próxima política no fluxo.
Por padrão, cada pacote cliente cria um pipeline configurado para funcionar com esse serviço específico do Azure. Você também pode definir suas próprias políticas personalizadas e inseri-las no pipeline HTTP ao criar um cliente.
Principais políticas de pipeline HTTP
O pacote Core fornece três políticas HTTP que fazem parte de cada pipeline:
Políticas de fluxo HTTP personalizadas
Você pode definir sua própria política personalizada para adicionar recursos além do conteúdo do pacote Core. Por exemplo, para ver como seu aplicativo lida com falhas de rede ou serviço, você pode criar uma política que injeta falha quando solicitações são feitas durante o teste. Ou você pode criar uma política que simula o comportamento de um serviço para teste.
Para criar uma política HTTP personalizada, defina sua própria estrutura com um Do
método que implementa a Policy
interface:
- O método da
Do
política deve executar operações conforme necessário na entradapolicy.Request
. Exemplos de operações incluem registro em log, injeção de uma falha ou modificação de qualquer url da solicitação, parâmetros de consulta ou cabeçalhos de solicitação. - O método
Do
encaminha a solicitação (modificada) para a próxima política no pipeline chamando o métodoNext
da solicitação. -
Next
retorna ohttp.Response
e um erro. Sua política pode executar qualquer operação necessária, como registrar em log a resposta/erro. - Sua política deve retornar uma resposta e um erro de volta à política anterior no pipeline.
Observação
As políticas devem ser goroutine-safe. A segurança de goroutines permite que várias goroutines acessem simultaneamente um único objeto de cliente. É comum que uma política seja imutável após a criação. Essa imutabilidade garante que a goroutine esteja segura.
Modelo de política personalizado
O código a seguir pode ser usado como ponto de partida para definir uma política personalizada.
type MyPolicy struct {
LogPrefix string
}
func (m *MyPolicy) Do(req *policy.Request) (*http.Response, error) {
// Mutate/process request.
start := time.Now()
// Forward the request to the next policy in the pipeline.
res, err := req.Next()
// Mutate/process response.
// Return the response & error back to the previous policy in the pipeline.
record := struct {
Policy string
URL string
Duration time.Duration
}{
Policy: "MyPolicy",
URL: req.Raw().URL.RequestURI(),
Duration: time.Duration(time.Since(start).Milliseconds()),
}
b, _ := json.Marshal(record)
log.Printf("%s %s\n", m.LogPrefix, b)
return res, err
}
func ListResourcesWithPolicy(subscriptionID string) error {
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
return err
}
mp := &MyPolicy{
LogPrefix: "[MyPolicy]",
}
options := &arm.ConnectionOptions{}
options.PerCallPolicies = []policy.Policy{mp}
options.Retry = policy.RetryOptions{
RetryDelay: 20 * time.Millisecond,
}
con := arm.NewDefaultConnection(cred, options)
if err != nil {
return err
}
client := armresources.NewResourcesClient(con, subscriptionID)
pager := client.List(nil)
for pager.NextPage(context.Background()) {
if err := pager.Err(); err != nil {
log.Fatalf("failed to advance page: %v", err)
}
for _, r := range pager.PageResponse().ResourceListResult.Value {
printJSON(r)
}
}
return nil
}
Transporte HTTP personalizado
Um transporte envia uma solicitação HTTP e retorna sua resposta/erro. A primeira política para lidar com a solicitação também é a última política que manipula a resposta antes de retornar a resposta/erro de volta às políticas do pipeline (em ordem inversa). A última política no fluxo de trabalho invoca o transporte.
Por padrão, os clientes usam o compartilhado http.Client
da biblioteca padrão do Go.
Você cria um transporte personalizado com estado ou sem estado da mesma forma que cria uma política personalizada. No caso com estado, você implementa o método Do
herdado da interface Transporter. Em ambos os casos, sua função ou Do
método recebe novamente um azcore.Request
, retorna um azCore.Response
e executa ações na mesma ordem que uma política.
Como excluir um campo JSON ao invocar uma operação do Azure
Operações como JSON-MERGE-PATCH
enviar um JSON null
para indicar que um campo deve ser excluído (juntamente com seu valor):
{
"delete-me": null
}
Esse comportamento entra em conflito com o marshaling padrão do SDK que especifica omitempty
como uma maneira de resolver a ambiguidade entre um campo a ser excluído e seu valor zero.
type Widget struct {
Name *string `json:",omitempty"`
Count *int `json:",omitempty"`
}
No exemplo anterior, Name
e Count
são definidos como ponteiro para tipo para desambiguar entre um valor ausente (nil
) e um valor zero (0), que pode ter diferenças semânticas.
Em uma operação PATCH HTTP, todos os campos com o valor nil
não afetam o valor no recurso do servidor. Ao atualizar o campo de Count
um Widget, especifique o novo valor para Count
, deixando Name
como nil
.
Para atender ao requisito de envio de um JSON null
, a NullValue
função é usada:
w := Widget{
Count: azcore.NullValue(0).(*int),
}
Esse código define Count
como um JSON null
explícito. Quando a solicitação é enviada ao servidor, o campo do Count
recurso é excluído.