Loupe

DocumentDB : l’expiration automatique des documents

Dans un précédent article, j’avais abordé le fait que DocumentDB souffrait du manque de la fonctionnalité : Time To Leave ou TTL. Désormais c’est supporté nativement par le service. Dans cet article nous allons voir quels sont les prérequis à son utilisation, son fonctionnement et sa mise en place.

 

Son rôle

Comme son nom l’indique c’est la détection des documents expirés et leur éviction de manière automatique. En effet, la gestion de la suppression des documents peut vite devenir problématique car cela :

  • Consomme des unités de requêtes (RU) : si le contexte le permet, il est conseillé de planifier cela la nuit ou lors de période de faible activité.
  • Complexifie votre architecture : il faut créer à minima une tâche, planifiée ou en arrière-plan, ou dans certains cas un sous-système.
  • Coûte en développement, en production : cette gestion doit être fiable, résiliente, surveillée, etc…

 

Son but est donc de permettre à ses utilisateurs de s’affranchir de cette contrainte. Pour l’activer, il faut définir une expiration par défaut au niveau de la collection qui sera appliquée sur chaque document qu’elle contient. Ensuite, il est possible de surcharger ce comportement avec un TTL défini au niveau du document lui-même.

 

Prérequis

Avant toute chose, pour bénéficier de cette fonctionnalité votre collection doit avoir une politique d’indexation « Lazy » ou « Consistent ». Si celle-ci est définie à « None », toute spécification du TTL par défaut se terminera par l’erreur suivante :

 

clip_image002

 

De même, dès lors qu’un TTL par défaut est défini il n’est plus possible de désactiver l’indexation sous peine également d’obtenir l’erreur précédente.

 

Son fonctionnement ?

Sur quoi s’appuie-t-il ?

L’expiration des documents repose sur le délai en secondes entre la date de dernière mise à jour (création ou modification) et l’heure du serveur.

Chaque document dans DocumentDB possède des propriétés internes qui sont maintenues par le système. Celle qui nous intéresse ici est la propriété « _ts » qui contient le temps unix (nombre de secondes écoulées le 01/01/1970) correspondant à sa dernière modification. Il est possible de récupérer sa valeur via le code ou via le portail Azure. Attention cependant l’explorateur de document disponible sur le portail n’affiche pas les propriétés systèmes, il faut utiliser l’explorateur de requête.

 

clip_image004

Explorateur de document

 

clip_image006

Explorateur de requête

 

Pour bien comprendre le fonctionnement du TTL, voici la matrice prenant compte des configurations possibles :

 

 

TTL par défaut non défini/manquant sur la collection

TTL par défaut = –1 sur la collection

TTL par défaut = y sur la collection

TTL manquant sur le document

Aucune expiration

Aucune expiration pour tous les documents de la collection.

Expiration TTL par défaut = y pour tous les documents.

TTL = –1 sur le document

Aucune expiration.

La propriété n’est pas interprétée par le moteur car rien n’est défini au niveau de la collection.

Aucune expiration pour tous les documents de la collection.

Pas d’expiration pour ce document.

Les autres documents ont une expiration TTL par défaut = y.

TTL = x sur le document

Aucune expiration.

La propriété n’est pas interprétée par le moteur car rien n’est défini au niveau de la collection.

Expiration TTL = x pour le document. 

Les autres documents n’expirent jamais.

Expiration TTL = x pour le document.

Les autres documents ont une expiration TTL par défaut = y.

 

Si un TTL est spécifié sur le document et celui sur la collection est manquant ou non défini, alors aucune expiration n’est appliquée par le système. Cependant, si par la suite un TTL par défaut est appliqué sur la collection, l’expiration s’applique sur les données existantes.

 
Sur quoi s’applique-t-il ?

Le TTL s’applique uniquement sur le document en entier. Il n’est pas possible de le spécifier sur une ou plusieurs propriétés de celui-ci. Si la problématique se présente, il est conseillé d’extraire la ou les propriétés concernées dans un document lié et d’appliquer l’expiration sur ce dernier.

 

Comment est-il vérifié ?

La vérification du TTL n’est pas un processus en arrière-plan avec une fréquence définie. Lorsque vous requêtez votre collection DocumentDB, le service vérifie à la volée s’il y a des documents qui ont expiré, les marque en tant que tels et les exclut de la réponse sans impacter votre quota de RU. Ce mode de fonctionnement permet à DocumentDB d’avoir un comportement identique quel que soit le nœud interrogé. Ainsi votre document devient indisponible au même moment à travers tous les réplicas sur l’ensemble des régions Azure où il est présent.

 

La suppression est-elle immédiate ?

La suppression physique est un processus en arrière-plan asynchrone qui n’impacte pas votre quota d’unité de requête et est géré par le service DocumentDB. Sa fréquence dépend de votre consommation sur la collection. Ainsi, un document marqué comme expiré continue d’exister physiquement durant une période indéterminée dans votre collection. Cependant, dès lors qu’un document est expiré, ce dernier n’est plus comptabilisé dans votre usage d’espace de stockage et ne sera plus retourné en réponse de vos requêtes.

 

Comment l’activer/désactiver ?

Au niveau de la collection
Via le code
private async Task CreateCollectionAsync(
    string databaseName,
    string collectionName,
    int? defaultTTL)
{
    var collection = new DocumentCollection
    {
        Id = collectionName,
        DefaultTimeToLive = defaultTTL
    };

    await client.CreateDocumentCollectionAsync(
        UriFactory.CreateDatabaseUri(databaseName),
        collection);
}
 
Via le portail

Sur le portail, il est possible de spécifier le TTL par défaut sur la collection à travers sa configuration. Les choix possibles sont :

  • « On » avec une valeur secondes
  • « On » : expiration infinie
  • « Off » : pas d’expiration

 

clip_image008

TTL par défaut sur la collection

Au niveau du document 

Via le code
C’est simple, il suffit de spécifier la propriété “TimeToLeave” de l’objet “Document”.

 

public async Task CreateDocumentOrReplaceAsync(
    int? ttl,
    Department department)
{
    Document document =
        client.CreateDocumentQuery(collectionUri)
            .Where(d => d.Id == department.Id)
            .AsEnumerable()
            .FirstOrDefault();

    if (document == null)
    {
        ResourceResponse<Document> response = 
            await client.CreateDocumentAsync(collectionUri, department);

        response.Resource.TimeToLive = ttl;
        await client.ReplaceDocumentAsync(response.Resource);
    }
    else
    {
        document.TimeToLive = ttl;
        await client.ReplaceDocumentAsync(document);
    }
}

 

Pour pouvoir spécifier un TTL à travers le code, il faut utiliser la version du SDK 1.7.0 ou supérieure.

 

Astuce 

Lorsque vous créez un document et spécifiez un TTL via le SDK celui-ci contient une propriété “ttl” avec la valeur spécifiée comme ceci :

 

TTL on document by SDK

TTL spécifié via la propriété du document

 

Dans l’exemple précédent, pour spécifier le TTL sur un nouveau document il faut d’abord le créer avec notre objet métier (ici un département) puis récupérer l’entité “Document” pour mettre à jour sa propriété “TimeToLeave”. Cela engendre un aller-retour supplémentaire à la base de données qui peut être évité. Pour ce faire, c’est très simple il suffit de créer dans notre objet métier une propriété du même nom comme ci-dessous, le moteur de base de données se comportera de manière identique :

public class Department
{
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }

    [JsonProperty(PropertyName = "departmentName")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "ttl")]
    public int? TTL { get; set; }
}

 

De cette manière vous pouvez modifier la méthode de création/mise à jour de document :

public async Task CreateDocumentOrReplaceAsync(Department department)
{
    Document document =
        client.CreateDocumentQuery(collectionUri)
            .Where(d => d.Id == department.Id)
            .AsEnumerable()
            .FirstOrDefault();

    if (document == null)
    {
        await client.CreateDocumentAsync(collectionUri, department);
    }
    else
    {
        await client.ReplaceDocumentAsync(document.SelfLink, department);
    }
}  
 
Via le portail

De la même manière, il est possible de créer un document avec la propriété “ttl” directement dans l’explorateur de document ou même uploader un JSON qui en contient plusieurs.

 

Create Document with Portail

Création d’un document via l’explorateur de document

 

 

Comment procéder si vous avez des données existantes ?

En fonction de votre besoin métier, expiration automatique par défaut des documents au niveau de la collection ou spécifique à chaque document, il est tout à fait possible d’expirer vos données existantes sans avoir besoin de les mettre à jour.

 

Cas n°1

Si vos données nécessitent une expiration globale quel que soit votre document, il suffit d’activer un TTL par défaut au niveau de la collection.

 

Cas n°2

Si au contraire une expiration doit être spécifique à chaque document, il est conseillé d’appliquer une expiration par défaut suffisamment longue sur la collection pour supprimer les anciennes données sans impacter les nouvelles. Une fois supprimées, appliquez une expiration par défaut infinie (-1) sur votre collection.

 

Conclusion

Comme nous avons pu le constater, les avantages de cette fonctionnalité sont multiples car :

  • C’est transparent en termes d’activation et d’utilisation (nécessite juste un update du package nuget de DocumentDB). Il n’y a pas de breaking change vis-à-vis de vos données existantes.
  • C’est gratuit et ne consomme pas d’unité de requête.
  • Cela simplifie votre architecture.

 

Enjoy !

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus