Udostępnij za pośrednictwem


Typowe wzorce użycia w zestawie Azure SDK dla języka Go

Pakiet Azure Core (azcore) w zestawie Azure SDK dla języka Go implementuje kilka wzorców stosowanych w całym zestawie SDK:

Stronicowanie (metody zwracające kolekcje)

Wiele usług platformy Azure zwraca kolekcje elementów. Ponieważ liczba elementów może być duża, te metody klienta zwracają pager, co pozwala aplikacji przetwarzać jedną stronę wyników naraz. Te typy są definiowane indywidualnie dla różnych kontekstów, ale mają wspólne cechy, takie jak NextPage metoda.

Załóżmy na przykład, że istnieje ListWidgets metoda zwracająca WidgetPagerwartość . Następnie użyj polecenia , WidgetPager jak pokazano poniżej:

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...
}

Długotrwałe operacje

Wykonanie niektórych operacji na platformie Azure może zająć dużo czasu — od kilku sekund do kilku dni. Przykłady takich operacji obejmują kopiowanie danych ze źródłowego adresu URL do obiektu blob magazynu lub trenowanie modelu sztucznej inteligencji w celu rozpoznawania formularzy. Te długotrwałe operacje (LROs) są źle dostosowane do standardowego przepływu HTTP stosunkowo szybkiego żądania i odpowiedzi.

Zgodnie z konwencją metody rozpoczynające LRO mają prefiks "Begin" i zwracają element Poller. Funkcja Poller jest używana do okresowego sondowania usługi do momentu zakończenia operacji.

W poniższych przykładach przedstawiono różne wzorce obsługi obiektów LROs. Więcej informacji można również znaleźć w kodzie źródłowym poller.go w zestawie SDK.

Blokowanie wywołania metody PollUntilDone

PollUntilDone obsługuje cały zakres operacji sondowania do momentu osiągnięcia stanu terminalu. Następnie zwraca ostateczną odpowiedź HTTP dla operacji sondowania z zawartością ładunku w interfejsie 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)

Niestandardowa pętla sondowania

Poll Wysyła żądanie sondowania do punktu końcowego sondowania i zwraca odpowiedź lub błąd.

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)

Wznawianie z poprzedniej operacji

Wyodrębnij i zapisz token wznowienia z istniejącego narzędzia Poller.

Aby wznowić sondowanie, może w innym procesie lub na innym komputerze, utwórz nowe PollerResponse wystąpienie, a następnie zainicjuj je, wywołując jego Resume metodę, przekazując wcześniej zapisany token wznawiania.

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)

Przepływ potoku HTTP

Różni klienci zestawu SDK zapewniają abstrakcję interfejsu API REST platformy Azure, aby umożliwić uzupełnianie kodu i bezpieczeństwo typu czasu kompilacji, dzięki czemu nie trzeba zajmować się mechaniką transportu niższego poziomu za pośrednictwem protokołu HTTP. Można jednak dostosować mechanikę transportu (na przykład ponawianie prób i rejestrowanie).

Zestaw SDK wysyła żądania HTTP za pośrednictwem potoku HTTP. Potok opisuje sekwencję kroków wykonywanych dla każdej rundy żądania HTTP.

Potok składa się z transportu wraz z dowolną liczbą zasad:

  • Transport wysyła żądanie do usługi i odbiera odpowiedź.
  • Każda zasada wykonuje określoną akcję w potoku.

Na poniższym diagramie przedstawiono przepływ potoku:

Diagram przedstawiający przepływ potoku.

Wszystkie pakiety klienckie współużytkuje pakiet Core o nazwie azcore. Ten pakiet konstruuje potok HTTP z uporządkowanym zestawem zasad, zapewniając, że wszystkie pakiety klienckie zachowują się spójnie.

Po wysłaniu żądania HTTP wszystkie zasady są uruchamiane w kolejności, w której zostały dodane do potoku przed wysłaniem żądania do punktu końcowego HTTP. Te zasady zwykle dodają nagłówki żądań lub rejestrują wychodzące żądanie HTTP.

Gdy usługa platformy Azure odpowie, wszystkie zasady są uruchamiane w odwrotnej kolejności, zanim odpowiedź powróci do kodu. Większość zasad ignoruje odpowiedź, ale zasady rejestrowania rejestrują odpowiedź. Zasady ponawiania mogą ponownie wysyłać żądanie, co zwiększa odporność aplikacji na błędy sieci.

Każda zasada jest dostarczana z wymaganymi danymi żądania lub odpowiedzi wraz z dowolnym kontekstem niezbędnym do uruchomienia zasad. Zasady zakończą operację z podanymi danymi, a następnie przekazują kontrolę do następnych zasad w potoku.

Domyślnie każdy pakiet klienta tworzy potok skonfigurowany do pracy z daną usługą platformy Azure. Możesz również zdefiniować własne zasady niestandardowe i wstawić je do potoku HTTP podczas tworzenia klienta.

Podstawowe zasady potoku HTTP

Pakiet Core zawiera trzy zasady HTTP, które są częścią każdego potoku:

Niestandardowe zasady potoku HTTP

Możesz zdefiniować własne zasady niestandardowe, aby dodać możliwości wykraczające poza zawartość pakietu Core. Aby na przykład zobaczyć, jak aplikacja zajmuje się awariami sieci lub usługi, można utworzyć zasady, które wprowadzają błąd podczas wykonywania żądań podczas testowania. Możesz też utworzyć zasady, które wyśmiewają zachowanie usługi na potrzeby testowania.

Aby utworzyć niestandardowe zasady HTTP, zdefiniuj własną Do strukturę za pomocą metody implementujące Policy interfejs:

  1. Metoda zasad Do powinna wykonywać operacje zgodnie z potrzebami w przychodzącym policy.Requestobiekcie . Przykłady operacji obejmują rejestrowanie, wstrzykiwanie błędu lub modyfikowanie dowolnego adresu URL żądania, parametrów zapytania lub nagłówków żądań.
  2. Metoda Do przekazuje żądanie (zmodyfikowane) do następnych zasad w potoku przez wywołanie metody żądania Next .
  3. Next zwraca wartość http.Response i błąd. Zasady mogą wykonać dowolną niezbędną operację, na przykład rejestrowanie odpowiedzi/błędu.
  4. Zasady muszą zwrócić odpowiedź i błąd z powrotem do poprzednich zasad w potoku.

Uwaga

Zasady muszą być bezpieczne. Bezpieczeństwo Goroutine umożliwia wielu goroutine dostęp do pojedynczego obiektu klienta jednocześnie. Często zasady są niezmienne po jej utworzeniu. Ta niezmienność gwarantuje, że goryna jest bezpieczna.

Szablon zasad niestandardowych

Poniższy kod może służyć jako punkt wyjścia do zdefiniowania zasad niestandardowych.

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
}

Niestandardowy transport HTTP

Transport wysyła żądanie HTTP i zwraca odpowiedź/błąd. Pierwsze zasady do obsługi żądania to również ostatnia zasada, która obsługuje odpowiedź przed zwróceniem odpowiedzi/błędu z powrotem do zasad potoku (w odwrotnej kolejności). Ostatnie zasady w potoku wywołują transport.

Domyślnie klienci używają biblioteki http.Client standardowej języka Go.

Niestandardowy transport stanowy lub bezstanowy jest tworzony w taki sam sposób, jak w przypadku tworzenia zasad niestandardowych. W przypadku stanowym implementujesz metodę Do dziedziczona z interfejsu usługi Transporter . W obu przypadkach funkcja lub Do metoda ponownie odbiera azcore.Requestelement , zwraca azCore.Responsewartość i wykonuje akcje w tej samej kolejności co zasady.

Jak usunąć pole JSON podczas wywoływania operacji platformy Azure

Operacje, takie jak JSON-MERGE-PATCH wysyłanie kodu JSON null w celu wskazania pola, powinny zostać usunięte (wraz z jego wartością):

{
    "delete-me": null
}

To zachowanie powoduje konflikt z domyślnym marshalingiem zestawu SDK, który określa omitempty jako sposób rozwiązania niejednoznaczności między polem, które ma zostać wykluczone i jego wartością zerową.

type Widget struct {
    Name *string `json:",omitempty"`
    Count *int `json:",omitempty"`
}

W poprzednim przykładzie i Count są definiowane jako wskaźnik do typu, Name aby uściślić różnice między brakującą wartością (nil) i wartością zero (0), które mogą mieć różnice semantyczne.

W operacji HTTP PATCH wszystkie pola o wartości nil nie wpływają na wartość w zasobie serwera. Podczas aktualizowania pola widżetu Count określ nową wartość elementu Count, pozostawiając Name jako nil.

Aby spełnić wymagania dotyczące wysyłania kodu JSON null, NullValue używana jest funkcja:

w := Widget{
    Count: azcore.NullValue(0).(*int),
}

Ten kod ustawia Count jawny kod JSON null. Po wysłaniu żądania do serwera pole zasobu Count zostanie usunięte.

Zobacz też