Gyakori használati minták az Azure SDK for Go-ban
Az Azure SDK for Go Azure Core (azcore
) csomagja számos, az SDK-ban alkalmazott mintát valósít meg:
- A HTTP-folyamat, amely az SDK ügyfélkódtárai által használt mögöttes HTTP-mechanizmus.
- Lapozás (gyűjteményeket visszaadó metódusok).
- Hosszú ideig futó műveletek (LPO-k).
Lapozás (gyűjteményeket visszaadó metódusok)
Számos Azure-szolgáltatás több elemgyűjteményt ad vissza. Mivel az elemek száma nagy lehet, ezek az ügyfélmetodusok egy Pager-t adnak vissza, amely lehetővé teszi, hogy az alkalmazás egyszerre egy oldalnyi eredményt dolgoz fel. Ezek a típusok egyedileg vannak definiálva a különböző környezetekhez, de közös jellemzőkkel rendelkeznek, például egy metódussal NextPage
.
Tegyük fel például, hogy van egy ListWidgets
metódus, amely egy WidgetPager
. Ezután használja az WidgetPager
itt látható módon:
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...
}
Hosszú ideig futó műveletek
Az Azure-beli műveletek némelyike hosszú időt vehet igénybe, akár néhány másodperctől néhány napig is. Ilyen műveletek például az adatok másolása egy forrás URL-címről egy tárolóblobba, vagy egy AI-modell betanítása az űrlapok felismerésére. Ezek a hosszú ideig futó műveletek (LPO-k) nem felelnek meg a viszonylag gyors kérések és válaszok szabványos HTTP-folyamatának.
Konvenció szerint az LRO-t kezdő metódusok "Start" előtaggal vannak elnevezve, és pollert adnak vissza. A Poller használatával rendszeres időközönként lekérdezhető a szolgáltatás, amíg a művelet be nem fejeződik.
Az alábbi példák az LPO-k kezelésének különböző mintáit szemléltetik. További információt az SDK poller.go forráskódjából is megtudhat.
A PollUntilDone hívásának letiltása
PollUntilDone
a lekérdezési művelet teljes időtartamát kezeli, amíg el nem éri a terminálállapotot. Ezután visszaadja a lekérdezési művelet végső HTTP-válaszát a felületen található respType
hasznos adat tartalmával.
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)
Testreszabott lekérdezési ciklus
Poll
lekérdezési kérelmet küld a lekérdezési végpontnak, és visszaadja a választ vagy a hibát.
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)
Folytatás egy korábbi műveletből
Bontsa ki és mentse az önéletrajz-jogkivonatot egy meglévő Pollerből.
A lekérdezés folytatásához , esetleg egy másik folyamatban vagy egy másik számítógépen hozzon létre egy új PollerResponse
példányt, majd inicializálja azt a metódus meghívásával Resume
, és adja át a korábban mentett folytatási jogkivonatot.
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-folyamat folyamata
A különböző SDK-ügyfelek absztrakciót biztosítanak az Azure REST API-ján keresztül a kódkiegészítés és a fordítási idő típusú biztonság érdekében, így nem kell foglalkoznia az alacsonyabb szintű átviteli mechanikával HTTP-en keresztül. Azonban testre szabhatja az átviteli mechanikát (például újrapróbálkozások és naplózás).
Az SDK HTTP-kéréseket küld egy HTTP-folyamaton keresztül. A folyamat leírja az egyes HTTP-kérés-válasz oda-vissza utakhoz végrehajtott lépések sorrendjét.
A folyamat egy átvitelből és tetszőleges számú szabályzatból áll:
- Az átvitel elküldi a kérést a szolgáltatásnak, és megkapja a választ.
- Minden szabályzat végrehajt egy adott műveletet a folyamatban.
Az alábbi ábra egy folyamat folyamatát szemlélteti:
Minden ügyfélcsomag rendelkezik egy Core-csomaggal.azcore
Ez a csomag a HTTP-folyamatot a szabályzatok rendezett készletével hozza létre, biztosítva, hogy minden ügyfélcsomag következetesen viselkedjen.
HTTP-kérés küldésekor az összes szabályzat abban a sorrendben fut, amelyben hozzáadták őket a folyamathoz, mielőtt a kérést elküldené a HTTP-végpontnak. Ezek a szabályzatok általában kérésfejléceket adnak hozzá, vagy naplózják a kimenő HTTP-kérést.
Az Azure-szolgáltatás válasza után az összes szabályzat fordított sorrendben fut, mielőtt a válasz visszatér a kódhoz. A legtöbb szabályzat figyelmen kívül hagyja a választ, de a naplózási szabályzat rögzíti a választ. Az újrapróbálkozás szabályzata újra kiadhatja a kérést, így az alkalmazás ellenállóbbá válik a hálózati hibáktól.
Minden szabályzathoz a szükséges kérelem- vagy válaszadatok, valamint a szabályzat futtatásához szükséges környezetek találhatók. A szabályzat végrehajtja a műveletet a megadott adatokkal, majd átadja az irányítást a folyamat következő szabályzatának.
Alapértelmezés szerint minden ügyfélcsomag létrehoz egy folyamatot, amely konfigurálva van az adott Azure-szolgáltatással való együttműködésre. Az ügyfél létrehozásakor saját egyéni szabályzatokat is meghatározhat, és beszúrhatja őket a HTTP-folyamatba.
Alapvető HTTP-folyamatszabályzatok
A Core csomag három HTTP-szabályzatot biztosít, amelyek minden folyamat részét képezik:
Egyéni HTTP-folyamatszabályzatok
Saját egyéni szabályzatot is meghatározhat, hogy a Core-csomag tartalmán túli képességeket adjon hozzá. Ha például azt szeretné látni, hogy az alkalmazás hogyan kezeli a hálózati vagy szolgáltatáshibákat, létrehozhat egy szabályzatot, amely hibát ad be a tesztelés során érkező kérések során. Létrehozhat egy olyan szabályzatot is, amely egy szolgáltatás viselkedését szimulálja a teszteléshez.
Egyéni HTTP-szabályzat létrehozásához definiálja saját struktúráját egy Do
olyan módszerrel, amely implementálja a Policy
felületet:
- A szabályzat metódusának szükség szerint végre kell hajtania
Do
a műveleteket a bejövőnpolicy.Request
. Ilyen műveletek például a naplózás, a hiba injektálása vagy a kérés URL-címének, a lekérdezési paramétereknek vagy a kérelemfejléceknek a módosítása. - A
Do
metódus a kérelem metódusának meghívásával továbbítja a (módosított) kérelmet a folyamat következő szabályzatánakNext
. Next
visszaadja ahttp.Response
hibát. A szabályzat bármilyen szükséges műveletet végrehajthat, például naplózhatja a választ/hibát.- A szabályzatnak vissza kell adnia egy választ és egy hibát a folyamat előző házirendjéhez.
Feljegyzés
A szabályzatnak goroutine-safenek kell lennie. A Goroutine biztonsága lehetővé teszi, hogy egyszerre több goroutine is hozzáférhessen egyetlen ügyfélobjektumhoz. A szabályzatok létrehozása után gyakran előfordul, hogy nem módosíthatók. Ez a megváltoztathatatlanság biztosítja, hogy a goroutine biztonságos legyen.
Egyéni szabályzatsablon
Az egyéni szabályzatok definiálásához az alábbi kód használható kiindulási pontként.
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
}
Egyéni HTTP-átvitel
Az átvitel HTTP-kérést küld, és visszaadja a válaszát/hibáját. A kérést elsőként kezelő szabályzat az utolsó szabályzat, amely kezeli a választ, mielőtt visszaküldené a választ/hibát a folyamat szabályzatainak (fordított sorrendben). A folyamat utolsó szabályzata meghívja az átvitelt.
Alapértelmezés szerint az ügyfelek a Go standard kódtárából származó megosztottat http.Client
használják.
Egyéni állapotalapú vagy állapot nélküli átvitelt ugyanúgy hozhat létre, mint egy egyéni szabályzatot. Az állapotalapú esetben a Do
Transporter felülettől örökölt metódust implementálja. Mindkét esetben a függvény vagy Do
metódus ismét kap egy azcore.Request
, egy visszaadott azCore.Response
, és a műveletet ugyanabban a sorrendben hajtja végre, mint egy szabályzat.
JSON-mező törlése Azure-művelet meghívásakor
Olyan műveletek, mint például JSON-MERGE-PATCH
a JSON null
küldése egy mező törlésének jelzésére (az értékével együtt):
{
"delete-me": null
}
Ez a viselkedés ütközik az SDK alapértelmezett marshalingjával, amely a kizárandó mező és a nulla érték közötti kétértelműség feloldására szolgál omitempty
.
type Widget struct {
Name *string `json:",omitempty"`
Count *int `json:",omitempty"`
}
Az előző példában Name
egy hiányzó érték (nil
) és Count
egy nulla (0) közötti egyértelműsítés érdekében mutató-típusként vannak definiálva, amelynek szemantikai eltérései lehetnek.
HTTP PATCH-művelet esetén az értékkel nil
rendelkező mezők nem befolyásolják a kiszolgáló erőforrásának értékét. Widget mezőjének Count
frissítésekor adja meg az új értéket Count
, és hagyja a Name
következőt: nil
.
A JSON null
küldésére vonatkozó követelmény teljesítéséhez a függvény a NullValue
következőt használja:
w := Widget{
Count: azcore.NullValue(0).(*int),
}
Ez a kód explicit JSON-értékre null
van halmazvaCount
. Amikor a kérést elküldi a kiszolgálónak, az erőforrás mezője Count
törlődik.