Édition

Share via


Opérations Gridwich pour Stockage Azure

Stockage Azure

Le service de Stockage Azure Gridwich, Gridwich.SagaParticipants.Storage.AzureStorage, fournit des opérations de blob et de conteneur pour les comptes Stockage Azure qui sont configurés pour Gridwich. Créer un blob, Supprimer un conteneur, Copier un blob ou Changer de niveau de stockage sont des exemples d’opérations de stockage.

Gridwich exige que ses mécanismes de stockage fonctionnent à la fois pour les objets blob de blocs Stockage Azure et pour les conteneurs. Avec des classes et des opérations de service de stockage distinctes pour les blobs et les conteneurs, il n’y a aucune ambiguïté quant au fait qu’une opération de stockage donnée se rapporte à un blob ou à un conteneur. Sauf mention contraire, cet article s’applique à la fois aux blobs et aux conteneurs.

Gridwich expose la plupart des opérations de stockage à des systèmes externes au sein du participant à la sagaStorage.AzureStorage. D’autres participants à la saga utilisent le service de stockage pour des tâches telles que la copie de blobs entre différents conteneurs ou comptes lorsqu’ils mettent en place des workflows d’encodage.

Cet article décrit comment le service de stockage Azure Gridwich répond aux exigences de la solution et s’intègre à des mécanismes tels que les gestionnaires d’événements. Les liens renvoient au code source correspondant, qui contient des commentaires plus détaillés sur les conteneurs, les classes et les mécanismes.

Kit de développement logiciel (SDK) Stockage Azure

Gridwich utilise les classes du SDK Stockage Azure pour interagir avec Stockage Azure, ce qui vous évite de rédiger des requêtes REST manuellement. Dans le fournisseur de stockage, les classes BlobBaseClient et BlobContainerClient du Kit de développement logiciel (SDK) gèrent les demandes de stockage.

Ces classes clientes du kit de développement logiciel (SDK) autorisent actuellement l’accès indirect uniquement aux deux en-têtes HTTP que Gridwich doit manipuler, x-ms-client-request-id pour le contexte de l’opération et ETag pour la version de l’objet.

Dans Gridwich, une paire de classes de fournisseurs distribue les fonctionnalités BlobBaseClientProvider et BlobContainerClientProvider dans des unités appelées manches. Pour plus d’informations sur les manches, consultez Manches de stockage.

Le diagramme suivant illustre la structure des classes SDK et Gridwich, ainsi que la manière dont les instances sont liées entre elles. Les flèches indiquent « a une référence à ».

Diagram showing client object instance relationships between the Storage SDK classes.

Stratégie de pipeline

Vous définissez le hook pour manipuler les en-têtes HTTP en tant qu’instance de stratégie de pipeline lorsque vous créez l'instance client. Vous ne pouvez définir cette stratégie qu’au moment de la création de l’instance du client et vous ne pouvez pas modifier la stratégie. Le code du fournisseur de stockage utilisant le client doit pouvoir manipuler les valeurs d’en-tête pendant l’exécution. Le défi consiste à faire en sorte que le fournisseur de stockage et le pipeline interagissent correctement.

Pour la stratégie de pipeline Gridwich, consultez la classe BlobClientPipelinePolicy.

Mise en cache du service de stockage

L’établissement de la connexion TCP et l’authentification entraînent une surcharge lorsqu’une instance d’objet client du SDK envoie sa première requête à Stockage Azure. Plusieurs appels au même objet blob dans une requête de système externe, par exemple obtenir les métadonnées, puis supprimer le blob, composé de la surcharge.

Pour atténuer la surcharge, Gridwich gère un cache d’une instance cliente pour chaque objet blob ou conteneur de stockage, en fonction des classes du kit de développement logiciel (SDK) utilisées par le contexte d’opération. Gridwich conserve cette instance cliente et peut l’utiliser pour plusieurs opérations de Stockage Azure sur le même objet blob ou conteneur pendant la durée d’une requête de système externe.

Les classes clientes fournies par le kit de développement logiciel (SDK) Azure requièrent que les instances d’objet client SDK soient spécifiques à un seul objet blob ou conteneur au moment de la création. Les instances ne sont pas non plus garanties pour une utilisation simultanée sur des threads différents. Étant donné qu’un contexte d’opération représente une requête unique, Gridwich base la mise en cache sur la combinaison d’un objet blob ou d’un nom de conteneur avec un contexte d’opération.

Cette réutilisation, combinée à la structure du client du kit de développement logiciel (SDK) Stockage Azure, requiert du code de prise en charge supplémentaire pour équilibrer l’efficacité et la clarté du code.

Argument de contexte

Presque toutes les opérations Gridwich Storage Service nécessitent un argument contextuel spécial de type StorageClientProviderContext. Cet argument de contexte répond aux spécifications suivantes :

  • Fournit au système externe des réponses, qui comprennent la valeur unique par requête du contexte d’opération basé sur JSON que le système externe a spécifié dans la requête Gridwich. Pour plus d’informations, consultez Contexte d’opération.

  • Permet aux appelants du service de stockage, comme les gestionnaires d’événements Gridwich, de contrôler les réponses visibles par le système externe. Ce contrôle permet d'éviter que le service n’inonde le système externe avec des événements de notification non pertinents. Pour plus d'informations, consultez Mise en sourdine du contexte.

  • Conforme aux conventions Stockage Azure pour garantir des requêtes et des réponses cohérentes dans un environnement qui permet un mélange de lecteurs et d’auteurs parallèles. Par exemple, prend en charge le suivi d’étiquettes d’entité. Pour plus d'informations, consultez ETags.

Contexte de stockage

Pour les types de stockage blob et conteneur, le contexte est StorageClientProviderContext, qui ressemble à ceci :

    string  ClientRequestID { get; }
    JObject ClientRequestIdAsJObject { get; }
    bool    IsMuted { get; set; }
    string  ETag { get; set; }
    bool    TrackingETag { get; set; }

Les deux premières propriétés sont des représentations différentes du contexte d’opération qui a été utilisé pour initialiser l’instance StorageClientProviderContext. La classe dispose d’une variété de constructeurs, y compris une copie du constructeur. Parmi les autres méthodes, on peut citer la méthode ResetTo, qui permet la duplication d’états sur place, et une méthode statique CreateSafe qui garantit que les initialisations problématiques ne créent pas d’exceptions.

La classe inclut également une gestion spéciale pour la création de contextes basés sur des GUID et des chaînes vides. Le format GUID est requis par les gestionnaires de notification de Stockage Azure pour le blob Créé et Supprimé, qui traitent également les notifications provenant d’agents externes.

Mise en sourdine du contexte

La propriété IsMuted détermine si l’application s’attend à ce que le service publie les notifications résultantes en retour à l’appelant, par exemple au système externe. Dans une opération en sourdine, le service ne publie pas les événements résultants.

Par exemple, les copies d’objets blob qui sont exécutées par un encodeur pour réorganiser les objets blob dans Stockage Azure en tant qu’entrée d’une tâche d’encodage. Le système externe ne se préoccupe pas de ces détails, mais seulement de l’état de la tâche d’encodage et de l’emplacement de récupération des sorties encodées. Pour tenir compte de ces préoccupations, l’encodeur :

  1. Crée un contexte de stockage non muet basé sur le contexte de l’opération de requête, par exemple ctxNotMuted.

  2. Crée un contexte de stockage muet, par exemple ctxMuted, soit en utilisant le constructeur de copie de la classe de contexte, soit en créant une nouvelle instance. L’une ou l’autre option aura la même valeur de contexte d’opération.

  3. Spécifie ctxMuted pour les opérations de stockage impliquées dans la mise en place de l’encodage. Le système externe ne voit aucune indication de ces opérations.

  4. Spécifie le contexte ctxNotMuted pour les opérations de stockage qui reflètent l’achèvement de l'encodage, par exemple la copie d’un fichier de sortie vers un conteneur cible. Les gestionnaires Gridwich publient les événements de notification Stockage Azure qui en résultent dans le système externe.

L’appelant contrôle la visibilité ultime des opérations. Les opérations avec et sans sourdine sont basées sur une valeur operationContext équivalente . L’intention de la mise en sourdine du contexte est de faciliter le diagnostic des problèmes à partir des journaux de suivi des événements, car il est possible de voir les opérations de stockage liées à une requête, quel que soit l’état de la mise en sourdine des opérations.

ResponseBaseDTO possède une propriété booléenne DoNotPublish, que le répartition des événements utilise pour dicter la décision finale de publier ou non. La répartition des événements, à son tour, définit la propriété DoNotPublish sur la base de la propriété IsMuted du contexte.

Le service transmet le paramètre de mise en sourdine à Stockage Azure, qui définit ensuite le clientRequestId dans les événements de notification de stockage qu’il présente aux deux gestionnaires Gridwich, Créé et Supprimé. Ces deux gestionnaires ont réglé DoNotPublish pour refléter la mise en sourdine demandée par l’appelant.

ETags pour la cohérence cible

Stockage Microsoft Azure utilise l'en-tête HTTP ETag pour les séquences de requête qui doivent avoir une cohérence cible. Il s’agit par exemple de s’assurer qu’un blob n’a pas changé entre les opérations de stockage Récupérer les métadonnées et Mettre à jour les métadonnées.

Pour s’aligner sur l'utilisation standard de HTTP, cet en-tête possède une valeur opaque signifiant que si la valeur de l’en-tête change, alors l’objet sous-jacent a également changé. Si une requête envoie sa valeur d’ETag actuelle pour l’objet et qu’elle ne correspond pas à la valeur d’ETag actuelle du service de stockage, la requête échoue immédiatement. Si la requête n’inclut pas de valeur ETag, Stockage Azure ignore cette vérification et ne bloque pas la requête.

ETags dans le service de stockage

Pour Gridwich, l’ETag constitue un détail interne entre le service de stockage Gridwich et Stockage Azure. Aucun autre code n’a besoin de connaître l’ETag. Le service de stockage utilise l’ETag pour des séquences comme les opérations Obtenir les métadonnées de blob, Supprimer le blob pour le traitement d’une requête BlobDelete Event. L’utilisation de l’ETag garantit que l’opération Supprimer l’objet blob cible exactement la même version du blob que l’opération Obtenir les métadonnées.

Pour utiliser l’ETag dans le cadre de l’exemple précédent :

  1. Envoyez la requête Obtenir les métadonnées avec un ETag vide.
  2. Enregistrez la valeur d’ETag de la réponse.
  3. Ajoutez la valeur d’ETag enregistrée à la requête Supprimer l’objet blob.

Si les deux valeurs d’ETag sont différentes, l’opération de suppression échoue. L’échec implique qu’une autre opération a modifié le blob entre les étapes 2 et 3. Répétez le processus à partir de l’étape 1.

ETag est un paramètre des constructeurs et une propriété de chaîne de la classe StorageClientProviderContext. Seule la stratégie BlobClientPipelinePolicy spécifique à Gridwich manipule la valeur de l’ETag.

Contrôler l’utilisation de l’ETag

La propriété TrackingETag détermine si la valeur d’ETag doit être envoyée lors de la prochaine requête. La valeur true signifie que le service envoie un ETag s’il y en a une de disponible.

Une requête Stockage Azure avec une valeur d’ETag qui ne correspond pas au blob ou au conteneur en question entraîne l’échec de l’opération. Cet échec est voulu, car l’ETag est le moyen HTTP standard d’exprimer « la version exacte visée par la demande ». Les requêtes peuvent inclure la propriété TrackingETag pour indiquer que les ETags doivent correspondre, ou ne pas inclure la propriété TrackingETag pour indiquer que les valeurs ETag n’ont pas d’importance.

Le pipeline récupère toujours une valeur d’ETag d’une opération Stockage Azure si elle est présente dans cette réponse REST. Le pipeline met toujours à jour la propriété du contexte ETag, si possible, à partir de la dernière opération. L’indicateur TrackingETag détermine uniquement si la requête suivante de la même instance de client envoie la valeur de la propriété ETag. Si la valeur ETag est nulle ou vide, la requête actuelle ne fixe aucune valeur HTTP ETag, quelle que soit la valeur de TrackingETag.

Manches de stockage

Gridwich exige que ses mécanismes de stockage fonctionnent à la fois pour les objets blob de blocs Stockage Azure et pour les conteneurs. Avec des classes et des opérations de service de stockage distinctes pour les blobs et les conteneurs, il n’y a aucune ambiguïté quant au fait qu’une opération de stockage donnée se rapporte à un blob ou à un conteneur.

Une paire de classes de fournisseurs, l’une pour les blobs et l’autre pour les conteneurs, dispensent les deux ensembles de fonctionnalités en unités appelées manches. Les manches contiennent des instances de classes d’assistance de stockage qui font partie du kit de développement logiciel (SDK) Azure. L’initialisation du service de stockage crée les fournisseurs et les met directement à la disposition des méthodes du service de stockage.

Structure de manche

La manche est un conteneur pour l’instance de l'objet SDK Client et un contexte de stockage. Les fonctions du fournisseur de stockage référencent la manche via les deux propriétés Client et Context. Il existe un type de manche pour les blobs et un autre pour les conteneurs, qui ont respectivement des propriétés Client de type BlobBaseClient et BlobContainerClient.

La structure générale de manche pour les blobs ressemble à ceci :

    BlobBaseClient Client { get; }
    BlobServiceClient Service { get; }
    StorageClientProviderContext Context { get; }

La propriété Service sur la manche est fournie à des fins de commodité. Certaines des opérations finales liées à l’encodeur qui utilisent la classe BlobServiceClient du Kit de développement logiciel (SDK) nécessitent des clés de compte de stockage. Cette exigence a conduit à l’ajout d’une instance cliente de service aux deux types de manche existants plutôt qu’à la production d’un fournisseur distinct.

Utilisation de manches

Les fournisseurs de stockage des clients dispensent des instances de manche. Le code du service de stockage ressemble à la séquence de code annotée suivante, les types étant épelés pour plus de clarté :

    public bool DeleteBlob(Uri sourceUri, StorageClientProviderContext context)
    {
        . . .
        StorageBlobClientSleeve sleeve = _blobBaseClientProvider.GetBlobBaseClientForUri(sourceUri, context); // Line A
        BlobProperties propsIncludingMetadata = sleeve.Client.GetProperties(); // Line B
        sleeve.Context.TrackingETag = true;   // Send ETag from GetProperties()
        var wasDeleted = sleeve.Client.DeleteBlob(); // Line C
        sleeve.Context.TrackingETag = false;
        var someResult = sleeve.Client.AnotherOperation(); // Line D
        . . .
    }
  1. Gridwich remplit automatiquement le contexte de l’opération dans le contexte de la manche à la ligne A. TrackingETag est false par défaut.
  2. Après la ligne B, sleeve.Context contient l’ETag de la ligne A et conserve la même valeur ClientRequestID.
  3. La ligne C envoie à la fois la valeur ETag de la ligne B et la valeur ClientRequestId.
  4. Après la ligne C, le contexte a une nouvelle valeur ETag, telle que retournée dans la réponse Delete().
  5. La ligne D n’envoie pas de valeur ETag à la requête de AnotherOperation().
  6. Après la ligne D, le contexte a une nouvelle valeur ETag, telle que retournée dans la réponse AnotherOperation().

Le service de stockage est actuellement défini en tant que Transient dans la configuration d’injection de dépendance, ce qui implique que la mise en cache basée sur les manches s’effectue sur demande. Consultez Service de stockage et injection de dépendance pour plus d’informations.

Alternatives au service de stockage

Les sections suivantes décrivent des approches alternatives qui ne font pas partie de la solution de stockage Gridwich actuelle.

Classe Gridwich AzureStorageManagement

En conjonction avec le membre de la manche Service, qui est une instance de la classe BlobServiceClient du Kit de développement logiciel (SDK) Azure, Gridwich possède également la classe AzureStorageManagement. La méthode Storage Service GetConnectionStringForAccount et la méthode d'encodage Telerek GetStoreByNameAsync utilisent cette classe pour obtenir des clés de compte de stockage. La classe est actuellement basée sur l’infrastructure Fluent. Les ajouts à la classe BlobServiceClient du Kit de développement logiciel (SDK) devraient à terme remplacer cette classe, permettant une recherche d’informations plus ciblée que la grande variété de l’interface Fluent IAzure.

Masquer la stratégie de pipeline via le sous-classement

Le sous-classement des types de clients du kit de développement logiciel (SDK) ajoute deux propriétés simples au client, une pour chaque valeur d’en-tête HTTP, afin de masquer complètement l’interaction avec la stratégie de pipeline. Mais en raison d’un bogue MOQ, il n’est pas possible de créer des tests unitaires via mock pour ces types dérivés. Gridwich utilise Moq et n’a donc pas eu recours à cette approche de sous-classement.

Le bogue Moq fait référence à la mauvaise gestion des sous-classes d’assembly en présence des fonctions virtuelles de portée interne. Les classes de clients SDK utilisent des fonctions virtuelles de portée interne impliquant des types de portée interne qui sont invisibles pour les utilisateurs extérieurs standards. Lorsque Moq tente de créer un mock de la sous-classe, qui se trouve dans un des assemblys Gridwich, il échoue au moment de l'exécution du test, car il ne peut pas trouver les virtuels de portée interne dans les classes clientes du SDK à partir desquelles les classes Gridwich sont dérivées. Il n’existe aucune solution de contournement sans modification dans la génération de proxy Moq Castle.

Service de stockage et injection de dépendances

Gridwich enregistre actuellement le service de stockage comme un service d’injection de dépendances Transient. Autrement dit, chaque fois qu’une injection de dépendances est demandée pour le service, elle crée une nouvelle instance. Le code actuel doit également fonctionner correctement si l’inscription devient Scoped, impliquant une instance par requête, par exemple la requête du système externe.

Toutefois, il y aura des problèmes si l’inscription devient Singleton, une instance dans l’application Gridwich Function. Le mécanisme de mise en cache Gridwich pour les manches et les plages d’octets de données ne distingue pas les différentes requêtes. En outre, le modèle de cache n’est pas un extrait, donc Gridwich ne supprime pas l’instance du cache pendant qu’il est en cours d’utilisation. Étant donné que le caractère « thread-safe » des classes clientes du SDK n’est pas garanti, la coordination requiert de nombreuses modifications.

Pour ces raisons, ne modifiez pas le service de stockage Gridwich, comme c’est le cas, pour l’inscription de l’injection de dépendances Singleton. Gridwich suit cette règle dans l’enregistrement de l’injection de dépendances et inclut un test unitaire, CheckThatStorageServiceIsNotASingleton, pour la faire respecter.

Étapes suivantes

Documentation du produit :

Modules Microsoft Learn :