Algemene gebruikspatronen in Azure SDK voor Go
Het pakket Azure Core ( azcore ) in Azure SDK voor Go implementeert verschillende patronen die overal in de SDK worden toegepast:
- De HTTP-pijplijnstroom,het onderliggende HTTP-mechanisme dat wordt gebruikt door de clientbibliotheken van de SDK.
- Paginering (methoden die verzamelingen retourneren).
- Langlopende bewerkingen (LRE's).
Paginering (methoden die verzamelingen retourneren)
Veel Azure-services retourneren verzamelingen items. Omdat het aantal items groot kan zijn, retourneren deze clientmethoden een Pager, waarmee uw app één pagina met resultaten tegelijk kan verwerken. Deze typen worden afzonderlijk gedefinieerd voor verschillende contexten, maar delen gemeenschappelijke kenmerken, zoals een NextPage methode.
Stel bijvoorbeeld dat er een methode is ListWidgets die een retourneert. WidgetPager Vervolgens gebruikt u de zoals WidgetPager hier wordt weergegeven:
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...
}
Zie het SDK-bronbestand zz_generated_pagers.go voor een voorbeeld van een Pager-implementatie.
Langlopende bewerkingen
Sommige bewerkingen in Azure kunnen lang duren, van een paar seconden tot enkele dagen. Voorbeelden van dergelijke bewerkingen zijn het kopiëren van gegevens van een bron-URL naar een opslagblob of het trainen van een AI-model om formulieren te herkennen. Deze langlopende bewerkingen (LRE's) zijn niet geschikt voor de standaard HTTP-stroom van een relatief snelle aanvraag en reactie.
Methoden die een LRO starten, worden volgens de conventies vooraf laten gaan door 'Begin' en retourneren een Poller. Poller wordt gebruikt om de service periodiek te peilen totdat de bewerking is uitgevoerd.
In de volgende voorbeelden ziet u verschillende patronen voor het afhandelen van LRO's. U kunt ook meer informatie vinden in de broncode poller.go in de SDK.
Aanroep naar PollUntilDone blokkeren
PollUntilDone verwerkt de hele periode van een pollingbewerking totdat een terminaltoestand is bereikt. Vervolgens wordt het uiteindelijke HTTP-antwoord voor de pollingbewerking met de inhoud van de nettolading in de respType opgegeven interface retourneert.
resp, err := client.BeginCreate(context.Background(), "blue_widget", nil)
if err != nil {
// Handle error...
}
// Second argument is the polling interval if the endpoint doesn't send a Retry-After header.
w, err = resp.PollUntilDone(context.Background(), 5*time.Second)
if err != nil {
// Handle error...
}
process(w)
Aangepaste poll-lus
Poll verzendt een polling-aanvraag naar het polling-eindpunt en retourneert het antwoord of een fout.
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)
Hervatten na een vorige bewerking
Extraheren en opslaan van het hervatten van het token uit een bestaande Poller.
Als u polling wilt hervatten, mogelijk in een ander proces of op een andere computer, maakt u een nieuw exemplaar en initialiseert u het door de methode aan te roepen en het eerder opgeslagen PollerResponseResume hervat-token door te geven.
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)
HTTP-pijplijnstroom
De verschillende clients bieden een abstractie via de HTTP-API van een Azure-service om de code te voltooien en de veiligheid van het type compilatietijd mogelijk te maken. U hebt dus geen te maken met transportmechanica op lager niveau. Maar u kunt de transportmechanica aanpassen (zoals nieuwe proberen en logboekregistratie).
De SDK doet HTTP-aanvragen via een HTTP-pijplijn. De pijplijn beschrijft de volgorde van de stappen die worden uitgevoerd voor elke retour met HTTP-aanvraag-antwoord.
De pijplijn bestaat uit een transport samen met een aantal beleidsregels:
- Het transport verzendt de aanvraag naar de service en ontvangt het antwoord.
- Elk beleid voltooit een specifieke actie in de pijplijn.
Dit diagram illustreert de stroom van een pijplijn:

Alle clientpakketten delen een Core-pakket met de naam . Met dit pakket wordt de HTTP-pijplijn samengesteld met de geordende set beleidsregels, zodat alle clientpakketten consistent werken.
- Wanneer een HTTP-aanvraag wordt verzonden, worden alle beleidsregels uitgevoerd in de volgorde waarin ze zijn toegevoegd aan de pijplijn voordat de aanvraag naar het HTTP-eindpunt wordt verzonden. Dit beleid voegt meestal aanvraagheaders toe of logboeken voor de uitgaande HTTP-aanvraag.
- Nadat de Azure-service heeft gereageerd, worden alle beleidsregels in omgekeerde volgorde uitgevoerd voordat het antwoord terugkeert naar uw code. De meeste beleidsregels negeren het antwoord, maar het logboekregistratiebeleid registreert het antwoord. Het beleid voor opnieuw proberen kan de aanvraag opnieuw uitgeven, waardoor uw app beter bestand is tegen netwerkfouten.
Elk beleid wordt geleverd met de benodigde aanvraag- of antwoordgegevens, samen met eventuele benodigde context voor het uitvoeren van het beleid. Het beleid voltooit de bewerking met de opgegeven gegevens en geeft vervolgens het besturingselement door aan het volgende beleid in de pijplijn.
Standaard maakt elk clientpakket een pijplijn die is geconfigureerd voor gebruik met die specifieke Azure-service. U kunt ook uw eigen aangepaste beleidsregels definiëren en deze invoegen in de HTTP-pijplijn wanneer u een client maakt.
Beleidsregels voor HTTP-kernpijplijnen
Het Core-pakket biedt drie HTTP-beleidsregels die deel uitmaken van elke pijplijn:
Aangepast beleid voor HTTP-pijplijnen
U kunt uw eigen aangepaste beleid definiëren om mogelijkheden toe te voegen die verder gaan dan wat is opgenomen in het Core-pakket. Als u bijvoorbeeld wilt zien hoe uw app omgaat met netwerk- of servicefouten, kunt u een beleid maken dat fouten veroorzaakt wanneer er tijdens het testen aanvragen worden gedaan. U kunt ook een beleid maken dat het gedrag van een service bespott voor testen.
Als u een aangepast HTTP-beleid wilt maken, definieert u uw eigen structuur met Do een methode waarmee de interface wordt Policy geïmplementeerd:
- De -methode van
Douw beleid moet zo nodig bewerkingen uitvoeren op de binnenkomendepolicy.Request. Voorbeelden van bewerkingen zijn logboekregistratie, het injecteren van een fout of het wijzigen van een van de aanvraag-URL's, queryparameters of aanvraagheaders. - Met
Dode methode wordt de aanvraag (gewijzigd) doorgestuurd naar het volgende beleid in de pijplijn door de methode van de aanvraag aan teNextroepen. Nextretourneerthttp.Responsede en een fout. Met uw beleid kan elke noodzakelijke bewerking worden uitgevoerd, zoals het vastleggen van het antwoord/de fout.- Uw beleid moet een antwoord en een fout retourneren naar het vorige beleid in de pijplijn.
Notitie
Beleidsregels moeten goroutine-safe zijn. Met goroutine-veiligheid hebben meerdere goroutines gelijktijdig toegang tot één clientobject. Het is gebruikelijk dat een beleid onveranderbaar is nadat het is gemaakt. Deze onveranderbaarheid zorgt ervoor dat de goroutine veilig is.
In de volgende sectie wordt gedemonstreerd hoe u een aangepast beleid definieert.
Beleidssjabloon
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
}
Aangepast HTTP-transport
Een transport verzendt een HTTP-aanvraag en retourneert de reactie/fout. Het transport wordt aangeroepen door het laatste beleid in de pijplijn. Dit is het eerste beleid dat het antwoord af handelen voordat het antwoord/de fout wordt teruggedraaid naar het beleid van de pijplijn (in omgekeerde volgorde).
Clients gebruiken standaard de gedeelde uit http.Client de standaardbibliotheek van Go.
U maakt een aangepaste stateful of staatloze transport op dezelfde manier als u een aangepast beleid maakt. In stateful gevallen implementeert u de methode Do die is overgenomen van de Do In beide gevallen ontvangt uw functie of methode opnieuw een , retourneert een en voert acties uit in dezelfde Doazcore.Request volgorde als een azCore.Response beleid.
Een JSON-veld verwijderen wanneer u een Azure-bewerking aanroept
Bewerkingen zoals JSON-MERGE-PATCH het verzenden van een JSON om aan te geven dat een veld moet worden verwijderd null (samen met de waarde):
{
"delete-me": null
}
Dit gedrag conflicteert met het standaardgedrag van de SDK dat aangeeft als een manier om de dubbelzinnigheid op te lossen tussen een veld dat moet worden uitgesloten en de omitempty nulwaarde.
type Widget struct {
Name *string `json:",omitempty"`
Count *int `json:",omitempty"`
}
In het voorgaande voorbeeld worden en gedefinieerd als pointer-to-type om onderscheid te maken tussen een ontbrekende waarde ( ) en een NameCount nul-waarde (0), die mogelijk semantische verschillen nil hebben.
In een HTTP PATCH-bewerking heeft elk veld waarvan de waarde is geen invloed op de nil waarde in de resource van de server. Wanneer u het veld van een widget Count bijwerkt, geeft u de nieuwe waarde voor Count op en laat u deze staan op Namenil .
Om te voldoen aan de vereiste voor het verzenden van een null JSON, wordt de functie NullValue gebruikt:
w := Widget{
Count: azcore.NullValue(0).(*int),
}
Met deze code wordt Count een expliciete JSON-code null gebruikt. Wanneer de aanvraag naar de server wordt verzonden, wordt het veld van de resource Count verwijderd.