Algemene gebruikspatronen in Azure SDK voor Go
Het Azure Core-pakket (azcore
) in Azure SDK voor Go implementeert verschillende patronen die 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 (LRO's).
Paginering (methoden die verzamelingen retourneren)
Veel Azure-services retourneren verzamelingen items. Omdat het aantal items groot kan zijn, retourneren deze clientmethoden een Pager, waardoor uw app één pagina met resultaten tegelijk kan verwerken. Deze typen worden afzonderlijk gedefinieerd voor verschillende contexten, maar delen algemene kenmerken, zoals een NextPage
methode.
Stel dat er een methode is die een ListWidgets
WidgetPager
. Vervolgens gebruikt u de WidgetPager
afbeelding zoals 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...
}
Langlopende bewerkingen
Het kan lang duren voordat sommige bewerkingen in Azure zijn voltooid, vanaf een paar seconden tot een paar 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 (LRO's) zijn slecht geschikt voor de standaard HTTP-stroom van een relatief snelle aanvraag en reactie.
Volgens de conventie worden methoden die een LRO starten voorafgegaan door 'Begin' en retourneren ze een Poller. De Poller wordt gebruikt om de service periodiek te peilen totdat de bewerking is voltooid.
In de volgende voorbeelden ziet u verschillende patronen voor het verwerken van LRO's. U kunt ook meer informatie vinden via de poller.go-broncode in de SDK.
Oproep naar PollUntilDone blokkeren
PollUntilDone
verwerkt het volledige bereik van een polling-bewerking totdat een terminalstatus is bereikt. Vervolgens wordt het uiteindelijke HTTP-antwoord voor de polling-bewerking geretourneerd met de inhoud van de nettolading in de respType
interface.
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)
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 vanaf een vorige bewerking
Pak het cv-token uit een bestaande poller en sla het op.
Als u polling wilt hervatten, misschien in een ander proces of op een andere computer, maakt u een nieuw PollerResponse
exemplaar en initialiseert u deze door de methode aan te roepen Resume
, waarbij het eerder opgeslagen cv-token wordt doorgegeven.
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 SDK-clients bieden een abstractie over de REST API van Azure om de beveiliging van code-voltooiing en compileertijd in te schakelen, zodat u niet te maken hebt met transportmechanica op lager niveau via HTTP. U kunt echter de transportmechanica aanpassen (zoals nieuwe pogingen en logboekregistratie).
De SDK doet HTTP-aanvragen via een HTTP-pijplijn. In de pijplijn wordt de volgorde beschreven van de stappen die worden uitgevoerd voor elke retour van een HTTP-aanvraag-antwoord.
De pijplijn bestaat uit een transport samen met een willekeurig aantal beleidsregels:
- Het transport verzendt de aanvraag naar de service en ontvangt het antwoord.
- Elk beleid voltooit een specifieke actie in de pijplijn.
In het volgende diagram ziet u de stroom van een pijplijn:
Alle clientpakketten delen een Core-pakket met de naam azcore
. 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. Deze beleidsregels voegen doorgaans aanvraagheaders toe of registreren de uitgaande HTTP-aanvraag.
Nadat de Azure-service reageert, worden alle beleidsregels uitgevoerd in de omgekeerde volgorde 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 verzenden, waardoor uw app toleranter wordt voor netwerkfouten.
Elk beleid wordt geleverd met de benodigde aanvraag- of antwoordgegevens, samen met de benodigde context voor het uitvoeren van het beleid. Het beleid voltooit de bewerking met de opgegeven gegevens en geeft vervolgens de controle 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.
Kernbeleid voor HTTP-pijplijnen
Het Core-pakket biedt drie HTTP-beleidsregels die deel uitmaken van elke pijplijn:
Aangepast HTTP-pijplijnbeleid
U kunt uw eigen aangepaste beleid definiëren om mogelijkheden toe te voegen buiten de inhoud van het Core-pakket. Als u bijvoorbeeld wilt zien hoe uw app omgaat met netwerk- of servicefouten, kunt u een beleid maken dat fouten injecteert wanneer er aanvragen worden gedaan tijdens het testen. U kunt ook een beleid maken waarmee het gedrag van een service wordt gesimuleerd voor het testen.
Als u een aangepast HTTP-beleid wilt maken, definieert u uw eigen structuur met een Do
methode waarmee de Policy
interface wordt geïmplementeerd:
- De methode van
Do
uw beleid moet zo nodig bewerkingen uitvoeren op de binnenkomendepolicy.Request
. Voorbeelden van bewerkingen zijn logboekregistratie, het injecteren van een fout of het wijzigen van de URL van de aanvraag, queryparameters of aanvraagheaders. - De
Do
methode stuurt de (gewijzigde) aanvraag door naar het volgende beleid in de pijplijn door de methode vanNext
de aanvraag aan te roepen. Next
retourneert dehttp.Response
en een fout. Uw beleid kan elke benodigde bewerking uitvoeren, 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 goroutineveiligheid kunnen meerdere goroutines gelijktijdig toegang krijgen tot één clientobject. Het is gebruikelijk dat een beleid onveranderbaar is nadat het is gemaakt. Deze onveranderbaarheid zorgt ervoor dat de goroutine veilig is.
Aangepaste beleidssjabloon
De volgende code kan worden gebruikt als uitgangspunt om een aangepast beleid te definiëren.
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 eerste beleid voor het afhandelen van de aanvraag is ook het laatste beleid dat het antwoord afhandelt voordat het antwoord/de fout wordt geretourneerd naar het beleid van de pijplijn (in omgekeerde volgorde). Het laatste beleid in de pijplijn roept het transport aan.
Clients gebruiken standaard de standaardbibliotheek http.Client
van Go.
U maakt een aangepast stateful of staatloos transport op dezelfde manier als u een aangepast beleid maakt. In het stateful geval implementeert u de Do
methode die is overgenomen van de Transporter-interface . In beide gevallen ontvangt uw functie of Do
methode opnieuw een azcore.Request
, retourneert een azCore.Response
en voert acties uit in dezelfde volgorde als een beleid.
Een JSON-veld verwijderen wanneer u een Azure-bewerking aanroept
Bewerkingen zoals JSON-MERGE-PATCH
een JSON null
verzenden om aan te geven dat een veld moet worden verwijderd (samen met de waarde):
{
"delete-me": null
}
Dit gedrag conflicteert met de standaard marshaling van de SDK die aangeeft omitempty
als een manier om de dubbelzinnigheid tussen een veld dat moet worden uitgesloten en de nulwaarde op te lossen.
type Widget struct {
Name *string `json:",omitempty"`
Count *int `json:",omitempty"`
}
In het voorgaande voorbeeld Name
worden Count
de aanwijzer-naar-type gedefinieerd om onderscheid te maken tussen een ontbrekende waarde (nil
) en een nulwaarde (0), die semantische verschillen kunnen hebben.
In een HTTP PATCH-bewerking hebben velden met de waarde nil
geen invloed op de waarde in de bron van de server. Wanneer u het veld van Count
een widget bijwerkt, geeft u de nieuwe waarde op voor Count
, waarbij u weggaat Name
als nil
.
De functie wordt gebruikt om te voldoen aan de vereiste voor het NullValue
verzenden van een JSONnull
:
w := Widget{
Count: azcore.NullValue(0).(*int),
}
Deze code wordt ingesteld Count
op een expliciete JSON null
. Wanneer de aanvraag naar de server wordt verzonden, wordt het veld van Count
de resource verwijderd.