Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Le package Azure Core (azcore
) dans le Kit de développement logiciel (SDK) Azure pour Go implémente plusieurs modèles appliqués dans le Kit de développement logiciel (SDK) :
- Le flux de pipeline HTTP, qui est le mécanisme HTTP sous-jacent utilisé par les bibliothèques client du SDK.
- Pagination (méthodes qui retournent des collections).
- Opérations de longue durée (LRO).
Pagination (méthodes qui retournent des collections)
De nombreux services Azure retournent des collections d’éléments. Étant donné que le nombre d’éléments peut être volumineux, ces méthodes clientes retournent un Pager, ce qui permet à votre application de traiter une page de résultats à la fois. Ces types sont définis individuellement pour différents contextes, mais partagent des caractéristiques communes, comme une NextPage
méthode.
Par exemple, supposons qu’il existe une ListWidgets
méthode qui retourne un WidgetPager
. Vous utiliserez ensuite l’élément WidgetPager
comme indiqué ici :
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...
}
Opérations de longue durée
Certaines opérations sur Azure peuvent prendre beaucoup de temps, de quelques secondes à quelques jours. Par exemple, ces opérations incluent la copie de données d’une URL source vers un objet blob de stockage ou l’apprentissage d’un modèle IA pour reconnaître les formulaires. Ces opérations longues (LRO) sont mal adaptées au flux HTTP standard d’une requête et d’une réponse relativement rapides.
Par convention, les méthodes qui démarrent un LRO sont précédées de « Begin » et retournent un Poller. Le Poller est utilisé pour interroger régulièrement le service jusqu’à ce que l’opération se termine.
Les exemples suivants illustrent différents modèles de gestion des LRO. Vous pouvez également en savoir plus à partir du code source poller.go dans le Kit de développement logiciel (SDK).
Blocage de l’appel à PollUntilDone
PollUntilDone
gère l'entièreté d’une opération d’interrogation jusqu’à ce qu’un état terminal soit atteint. Elle retourne ensuite la réponse HTTP finale pour l’opération d’interrogation avec le contenu de la charge utile dans l’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)
Boucle de sondage personnalisée
Poll
envoie une requête de sondage au point de terminaison de sondage et retourne la réponse ou une erreur.
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)
Reprendre à partir d’une opération précédente
Extrayez et enregistrez le jeton de reprise à partir d’un Poller existant.
Pour reprendre l’interrogation, peut-être dans un autre processus ou sur un autre ordinateur, créez une nouvelle PollerResponse
instance, puis initialisez-la en appelant sa Resume
méthode, en lui transmettant le jeton de reprise précédemment enregistré.
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)
Flux de pipeline HTTP
Les différents clients SDK offrent une abstraction par rapport à l'API REST d'Azure pour permettre la complétion de code et la sécurité des types au moment de la compilation, vous évitant ainsi de gérer les mécanismes de transport à un niveau inférieur via HTTP. Toutefois, vous pouvez personnaliser les mécanismes de transport (comme les tentatives de réessai et la journalisation).
Le Kit de développement logiciel (SDK) effectue des requêtes HTTP via un pipeline HTTP. Le pipeline décrit la séquence d’étapes effectuées pour chaque aller-retour de requête HTTP.
Le pipeline est composé d’un transport avec n’importe quel nombre de stratégies :
- Le transport envoie la requête au service et reçoit la réponse.
- Chaque stratégie termine une action spécifique dans le pipeline.
Le diagramme suivant illustre le flux d’un pipeline :
Tous les packages clients partagent un package Core nommé azcore
. Ce package construit le pipeline HTTP avec son ensemble ordonné de stratégies, ce qui garantit que tous les packages clients se comportent de manière cohérente.
Lorsqu’une requête HTTP est envoyée, toutes les stratégies s’exécutent dans l’ordre dans lequel elles ont été ajoutées au pipeline avant l’envoi de la requête au point de terminaison HTTP. Ces stratégies ajoutent généralement des en-têtes de requête ou journalisent la requête HTTP sortante.
Une fois que le service Azure répond, toutes les stratégies s’exécutent dans l’ordre inverse avant que la réponse ne retourne à votre code. La plupart des stratégies ignorent la réponse, mais la stratégie de journalisation enregistre la réponse. La stratégie de nouvelle tentative peut réécrire la requête, ce qui rend votre application plus résiliente aux défaillances réseau.
Chaque stratégie est fournie avec les données de requête ou de réponse nécessaires, ainsi que tout contexte nécessaire pour exécuter la stratégie. La politique termine son opération avec les données fournies, puis passe le contrôle à la politique suivante dans le pipeline.
Par défaut, chaque package client crée un pipeline configuré pour fonctionner avec ce service Azure spécifique. Vous pouvez également définir vos propres stratégies personnalisées et les insérer dans le pipeline HTTP lorsque vous créez un client.
Stratégies de pipeline HTTP principales
Le package Core fournit trois stratégies HTTP qui font partie de chaque pipeline :
Stratégies de pipeline HTTP personnalisées
Vous pouvez définir votre propre stratégie personnalisée pour ajouter des fonctionnalités au-delà du contenu du package Core. Par exemple, pour voir comment votre application traite des défaillances de réseau ou de service, vous pouvez créer une stratégie qui injecte une erreur lorsque les requêtes sont effectuées pendant les tests. Vous pouvez également créer une stratégie qui simulant le comportement d’un service pour les tests.
Pour créer une stratégie HTTP personnalisée, définissez votre propre structure avec une Do
méthode qui implémente l’interface Policy
:
- Votre stratégie de méthode
Do
doit effectuer des opérations selon les besoins sur l'entrantpolicy.Request
. Parmi les exemples d’opérations, citons la journalisation, l’injection d’un échec ou la modification de l’URL de la requête, des paramètres de requête ou des en-têtes de requête. - La méthode
Do
transfère la requête (modifiée) à la stratégie suivante dans le pipeline en appelant la méthodeNext
de la requête. -
Next
retournehttp.Response
et une erreur. Votre stratégie peut effectuer n’importe quelle opération nécessaire, comme la journalisation de la réponse/erreur. - Votre stratégie doit renvoyer une réponse et une erreur à la stratégie précédente dans le pipeline.
Remarque
Les stratégies doivent être goroutine-safe. La sécurité des goroutines permet à plusieurs goroutines d’accéder simultanément à un objet client unique. Il est courant qu’une stratégie soit immuable après la création. Cette immuabilité garantit que la goroutine est sûre.
Modèle de stratégie personnalisée
Le code suivant peut être utilisé comme point de départ pour définir une stratégie personnalisée.
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
}
Transport HTTP personnalisé
Un transport envoie une requête HTTP et retourne sa réponse/erreur. La première stratégie à gérer la requête est également la dernière stratégie qui gère la réponse avant de renvoyer la réponse/erreur aux stratégies du pipeline (dans l’ordre inverse). La dernière politique du pipeline invoque le transport.
Par défaut, les clients utilisent le http.Client
partagé de la bibliothèque standard de Go.
Vous créez un transport personnalisé, qu'il soit avec état ou sans état, de la même façon que vous créez une stratégie personnalisée. Dans le cas d'un système avec état, vous implémentez la méthode Do
qui est héritée de l’interface Transporter. Dans les deux cas, votre fonction ou Do
méthode, reçoit à nouveau un azcore.Request
, retourne un azCore.Response
, et effectue des actions dans le même ordre comme une politique.
Comment supprimer un champ JSON lorsque vous appelez une opération Azure
Les opérations comme JSON-MERGE-PATCH
envoient un JSON null
pour indiquer qu’un champ doit être supprimé (ainsi que sa valeur) :
{
"delete-me": null
}
Ce comportement est en conflit avec le marshaling par défaut du SDK qui spécifie omitempty
comme moyen de résoudre l’ambiguïté entre un champ à exclure et sa valeur nulle.
type Widget struct {
Name *string `json:",omitempty"`
Count *int `json:",omitempty"`
}
Dans l’exemple précédent, Name
et Count
sont définis comme pointeur vers type pour lever l’ambiguïté entre une valeur manquante (nil
) et une valeur nulle (0), ce qui peut avoir des différences sémantiques.
Dans une opération HTTP PATCH, tous les champs ayant la valeur nil
ne modifient pas la valeur de la ressource sur le serveur. Lors de la mise à jour du champ Count
d'un widget, spécifiez la nouvelle valeur pour Count
, en laissant Name
en tant que nil
.
Pour répondre à l’exigence d’envoi d’un JSON null
, la NullValue
fonction est utilisée :
w := Widget{
Count: azcore.NullValue(0).(*int),
}
Ce code définit Count
en un JSON null
explicite. Lorsque la demande est envoyée au serveur, le champ de Count
la ressource est supprimé.