Objets cache
CacheThing fournit une interface rapide en mémoire pour le stockage et la récupération des données clé/valeur. Il est idéal pour la mise en cache des résultats d'opérations coûteuses ou chronophages, telles que les requêtes lentes.
Etant donné que CacheThing fonctionne en mémoire, son contenu est effacé au redémarrage de ThingWorx. Dans les environnements haute disponibilité, chaque noeud ThingWorx conserve son propre cache indépendant. Par conséquent, les entrées de cache créées ou mises à jour sur un noeud ne sont pas automatiquement partagées avec les autres noeuds. Cela inclut les appels d'invalidation du cache, tels que PurgeCache, DeleteEntry et DeleteEntryByKey.
Vous pouvez utiliser CacheThing pour mettre en cache différents types de données, notamment les suivants :
Résultats de requêtes coûteuses ou fréquentes effectuées sur des objets de base de données
Résultats de requêtes coûteuses ou fréquentes effectuées sur des flux de valeurs ou des tables de données
Résultats des appels réseau lents, par exemple, les appels effectués avec les fonctions de chargeur de contenu
Valeurs calculées coûteuses
Contenu des petits fichiers fréquemment utilisés dans les référentiels de fichiers
L'utilisation de CacheThing peut considérablement améliorer les performances et réduire l'utilisation des ressources par rapport à l'accès à des systèmes externes tels que des bases de données ou des ressources réseau.
Consignes d'utilisation
CacheThing n'est pas destiné à être utilisé comme une banque de données permanente. Toutes les données mises en cache dans CacheThing doivent pouvoir être reproductibles à partir de la source d'origine.
Les données d'un objet cache peuvent expirer ou être évincées. Les services qui utilisent CacheThing doivent être conçus pour récupérer des données de la source d'origine si le cache ne renvoie aucun résultat. Pour plus d'informations, consultez les exemples.
Configuration
Les objets cache doivent être configurés avec une forme de données dotée d'une clé primaire. La clé primaire est utilisée pour récupérer les entrées du cache.
Les clés primaires composites sont prises en charge, mais elles empêchent l'utilisation des services de commodité ByKey, de la règle d'expiration et de la taille maximale globale décrits ci-dessous.
Règle d'expiration
La règle d'expiration définit la durée de vie (TTL) de chaque entrée du cache. Vous pouvez configurer le délai d'expiration à l'aide du paramètre Délai d'expiration des entrées de cache (secondes). Après l'expiration d'une entrée, la récupération de la valeur renvoie un résultat vide, comme si elle avait été supprimée du cache.
Règles d'expiration prises en charge :
Règle d'expiration des entrées de cache
Description
Jamais
L'entrée de cache n'est jamais supprimée sur la base de la durée de son séjour dans le cache. Toutefois, elle pourra toujours être évincée si le cache atteint la configuration de taille maximale ou à l'aide du service DeleteEntry. Le paramètre Délai d'expiration des entrées de cache (secondes) est ignoré lorsque la règle d'expiration Never est configurée.
Délai d'expiration depuis le dernier accès
L'entrée est supprimée si elle n'a pas été lue dans le délai d'expiration spécifié.
Délai d'expiration depuis la création
L'entrée est supprimée une fois que le temps spécifié s'est écoulé depuis sa création.
Délai d'expiration depuis la dernière modification
L'entrée est supprimée si elle n'a pas été modifiée dans le délai d'expiration spécifié.
Délai d'expiration depuis le dernier contact
L'entrée est supprimée si elle n'a pas été consultée ou modifiée dans le délai d'expiration spécifié.
Pour plus d'informations sur la règle d'expiration, consultez la page Interface ExpiryPolicy (en anglais).
Taille maximale du cache (éviction)
Les entrées de cache sont automatiquement évincées (supprimées) lorsque le cache atteint la taille spécifiée dans le paramètre Taille maximale du cache (Mo). Le processus d'éviction supprime les entrées les moins fréquemment utilisées (LFU) pour faire de la place à de nouvelles entrées. Une fois qu'une entrée est évincée, sa récupération renvoie un résultat vide, comme si elle avait été supprimée.
Si une entrée volumineuse est ajoutée, plusieurs entrées plus petites peuvent être évincées pour l'accueillir. Pour éviter cela, utilisez le service EstimateEntrySize pour vérifier la taille d'une entrée avant de l'ajouter au cache.
L'éviction et l'expiration du cache fonctionnent indépendamment :
L'éviction est basée sur la taille du cache et la fréquence d'utilisation.
L'expiration est basée sur le temps, tel que défini par la règle d'expiration configurée.
Taille maximale globale
Le sous-système de plateforme inclut un paramètre nommé Taille maximale partagée entre tous les objets cache par noeud ThingWorx (Mo). Ce paramètre limite la taille combinée de tous les objets cache sur un seul noeud afin d'éviter une utilisation excessive de la mémoire. Les objets cache désactivés ne sont pas inclus dans cette limite.
Cette configuration empêche les actions suivantes :
Création d'un nouvel objet cache qui dépasse la taille maximale
Mise à jour du paramètre Taille maximale du cache (Mo) d'un objet cache qui dépasse la taille maximale
Toute importation d'objets cache (en tant qu'importation d'entités ou en tant que partie d'une extension) qui entraînerait un dépassement de la taille maximale, avec pour effet de faire échouer l'importation dans son intégralité
Réduction de la taille maximale en deçà de la Taille maximale du cache (Mo) actuellement combinée de tous les objets cache
Toute activation d'un objet cache qui entraînerait un dépassement de limite globale
Modification de la configuration d'un cache
Toute modification apportée à la configuration d'un cache purgera automatiquement le cache afin de préserver la cohérence interne. Toute modification de l'un des éléments suivants purgera le cache :
Forme de données : inclut la modification de la forme de données configurée, notamment l'ajout ou la suppression de champs.
Règle d'expiration des entrées de cache
Délai d'expiration des entrées de cache (secondes)
Taille maximale du cache (Mo)
Cache Performs Loading of Missing Entries
Services
Les services suivants sont disponibles sur un objet cache. Dans les environnements haute disponibilité (HA), ils affectent le cache sur le noeud ThingWorx où le service est exécuté.
Les services de commodité *ByKey répertoriés ci-dessous ne sont disponibles que lorsque la forme de données du cache possède une clé primaire unique. Si la forme de données du cache comprend plusieurs clés primaires, utilisez la version d'entrée complète de la table d'informations du service.
Nom du service
Description
PutEntry
Ajoute une entrée au cache.
Valeur d'entrée : table d'informations d'une ligne utilisant la forme de données configurée de l'objet cache.
GetEntry
Renvoie un résultat de table d'informations d'une ligne issu du cache.
Si l'entrée est introuvable (cache manquant) et que le cache n'est pas configuré avec l'option Cache Performs Loading of Missing Entries, une table d'informations vide est renvoyée. Si le cache est configuré avec cette option, le service LoadEntry est appelé automatiquement et son résultat est renvoyé.
Des échecs de cache peuvent se produire si l'entrée n'a jamais été ajoutée au cache, a été supprimée ou a expiré.
Valeur d'entrée : table d'informations d'une ligne utilisant la forme de données configurée de l'objet cache. Seules les valeurs Primary Key doivent être renseignées.
GetEntryByKey
Renvoie un résultat de table d'informations d'une ligne issu du cache.
Si l'entrée est introuvable, une table d'informations vide est renvoyée. Des échecs de cache peuvent se produire si l'entrée n'a jamais été ajoutée au cache, a été supprimée ou a expiré.
Valeur d'entrée : chaîne représentant la clé primaire de l'entrée en cours de récupération. Ce service n'est disponible que si la forme de données possède une clé primaire unique. Il fonctionne mieux avec des clés primaires de type chaîne, mais prend également en charge la plupart des types avec une conversion de chaîne claire.
LoadEntry
Utilisé pour récupérer automatiquement les données de cache à partir de la source de données en cas de cache manquant.
Ce service doit être remplacé si l'option Cache Performs Loading of Missing Entries est activée.
DeleteEntry
Supprime une entrée du cache.
Dans un environnement haute disponibilité, cela affecte uniquement le noeud sur lequel le service DeleteEntry est appelé.
Valeur d'entrée : table d'informations d'une ligne utilisant la forme de données configurée de l'objet cache. Seules les valeurs Primary Key doivent être renseignées.
DeleteEntryByKey
Supprime une entrée du cache.
Dans un environnement haute disponibilité, cela affecte uniquement le noeud sur lequel le service DeleteEntryByKey est appelé.
Valeur d'entrée : chaîne représentant la clé primaire de l'entrée en cours de récupération. Ce service n'est disponible que si la forme de données possède une clé primaire unique.
PurgeCache
Supprime toutes les entrées du cache.
Dans un environnement haute disponibilité, cela affecte uniquement le noeud sur lequel le service PurgeCache est appelé.
GetDataShape
Renvoie la forme de données configurée du cache.
SetDataShape
Définit le champ de la forme de données dans la table de configuration du cache. Si vous modifiez cette valeur, le cache sera automatiquement purgé.
GetEstimatedEntryCount
Renvoie le nombre estimé d'entrées dans le cache. Les opérations PUT et DELETE en cours, ainsi que les processus d'expiration ou d'éviction, peuvent affecter la précision.
EstimateEntrySize
Renvoie la taille estimée d'une entrée si elle a été ajoutée au cache. Cette opération n'insère pas l'entrée dans le cache et ne nécessite aucune entrée déjà existante dans le cache. Ce service peut être utile pour estimer une Taille maximale du cache (Mo) ou pour empêcher l'ajout d'entrées volumineuses dans le cache.
Valeur d'entrée : table d'informations d'une ligne utilisant la forme de données configurée de l'objet cache.
Remplacement du service LoadEntry
Pour activer la mise en cache Cache Performs Loading of Missing Entries (cache en lecture), vous devez remplacer le service LoadEntry sur CacheThing. Ce service est appelé en interne en cas de cache manquant, ce qui permet au cache de récupérer et de stocker les données de la source.
L'appel direct du service LoadEntry n'ajoute pas d'entrées au cache. Les entrées ne sont ajoutées que lorsque LoadEntry est invoqué en interne par GetEntry en cas de cache manquant.
Entrée
L'entrée est une table d'informations d'une ligne qui correspond aux paramètres de l'appel GetEntry correspondant. En règle générale, seuls les champs de clé primaire sont renseignés.
Implémentation de service
Le service LoadEntry doit récupérer ou générer la valeur à mettre en cache à partir de la source de données. Il peut s'agir de requêtes de base de données, d'appels de services Web ou de valeurs générées. Evitez de mettre à jour l'état de l'application, tel que les propriétés ou fichiers, dans le service.
N'appelez pas d'autres services de mise en cache, tels que GetEntry ou PutEntry, à partir de LoadEntry. Le cache gère automatiquement le stockage de la valeur renvoyée après une erreur de cache manquant.
Sortie
La sortie doit être une table d'informations avec la même forme de données que l'entrée. Remplissez les champs de clé non primaire avec les données récupérées. Toutes les exceptions sont propagées à l'appel GetEntry en cours.
Il est recommandé de créer une nouvelle table d'informations pour les résultats de sortie. Bien qu'il soit possible de réutiliser et de remplir les valeurs d'entrée de la table d'informations, cela peut entraîner un comportement inattendu en raison des limitations de la façon dont les tables d'informations traitent certains types de base en JavaScript. Pour plus d'informations sur l'utilisation de LoadEntry, consultez les exemples.
Cache en lecture
Cocher la case Cache Performs Loading of Missing Entries active la mise en cache en lecture. Dans ce mode, le cache charge automatiquement les valeurs d'entrée manquantes à l'aide du service LoadEntry sur l'objet cache en cas de cache manquant.
Pour prendre en charge ce comportement, vous devez remplacer le service LoadEntry sur CacheThing afin d'interroger les données source et de renvoyer la valeur appropriée. Lorsque le service GetEntry ne trouve pas de valeur dans le cache, le cache appelle le service LoadEntry pour récupérer la valeur.
La mise en cache en lecture peut aider à atténuer les scénarios de type "thundering herd". Si plusieurs requêtes GetEntry parallèles sont effectuées pour la même clé avant qu'elle ne soit remplie, le service LoadEntry sous-jacent n'est appelé qu'une seule fois. Une fois l'appel LoadEntry terminé, toutes les requêtes GetEntry en attente renvoient la valeur récupérée.
Pour plus d'informations sur l'implémentation d'un service LoadEntry, consultez la section Remplacement du service LoadEntry ci-dessus.
Mesures
Plusieurs mesures liées au cache sont disponibles. Dans les environnements haute disponibilité (HA), les caches sont indépendants pour chaque noeud. Les mesures doivent être traitées par noeud à l'aide des étiquettes platform et cache_name.
Les mesures de cache suivantes sont disponibles :
Mesures de cache
Description
thingworx_cache_hit_rate
Ratio de requêtes en cache ayant abouti à la détection d'une entrée dans le cache
thingworx_cache_hits
Nombre de fois où les méthodes de consultation du cache ont renvoyé une valeur mise en cache
thingworx_cache_request_count
Nombre de fois où les méthodes de consultation du cache ont renvoyé une valeur mise en cache ou non mise en cache
thingworx_cache_miss_rate
Ratio des méthodes de consultation du cache ayant renvoyé une valeur non mise en cache (nouvellement chargée) ou une valeur nulle
thingworx_cache_misses
Nombre de fois où les méthodes de consultation du cache ont renvoyé une valeur non mise en cache (nouvellement chargée) ou une valeur nulle
thingworx_cache_eviction_count
Nombre de fois qu'une entrée a été évincée
thingworx_cache_average_load_penalty
Temps moyen de chargement des nouvelles valeurs
thingworx_cache_weighted_size
Taille actuelle approximative du cache en octets
thingworx_cache_max_weight
Taille maximale du cache en octets avant éviction
thingworx_cache_estimated_entry_count
Estimation du nombre d'entrées dans le cache
thingworx_cache_global_max_size
Taille maximale globale configurée pour tous les caches en octets
Alertes (disponibles dans les environnements hébergés dans le Cloud PTC)
Les alertes suivantes sont disponibles dans les environnements hébergés dans le Cloud PTC :
thingworxEntityCacheMissRate : alerte lorsque le taux d'échec d'un cache dépasse 80 % pendant 1 heure.
thingworxEntityCacheEvictions : alerte lorsque le taux d'éviction d'un cache dépasse 80 % pendant 30 minutes.
Exemples et bonnes pratiques
L'implémentation efficace de services qui utilisent un objet cache nécessite une attention particulière. Tenez compte des bonnes pratiques suivantes :
Le cache est effacé lorsque le noeud ThingWorx redémarre.
Les entrées du cache peuvent être évincées ou expirer sans action de l'utilisateur. Ne présumez pas qu'elles resteront indéfiniment dans le cache.
Utilisez les mesures de cache pour vérifier que son dimensionnement est approprié.
Evitez de stocker toutes les données sous une seule entrée ou de créer des entrées de cache très volumineuses.
Dans les environnements haute disponibilité (HA), chaque noeud possède un cache indépendant. L'ajout, la suppression ou la purge d'un cache sur un noeud n'affecte pas tous les noeuds ThingWorx.
Lorsque l'option Cache Performs Loading of Missing Entries est désactivée (hors cache en lecture) :
1. Récupérez une entrée du cache à l'aide de la clé primaire.
2. Vérifiez si le résultat est renseigné (la table d'informations renvoyée comporte une ligne).
3. Si le résultat est trouvé, utilisez-le.
4. Si aucun résultat n'est trouvé :
Récupérez ou générez l'entrée requise à partir des données sources (par exemple, objet de base de données, table de données ou chargeur de contenu).
Ajoutez l'entrée au cache à l'aide de PutEntry.
Renvoie la nouvelle entrée mise en cache.
Lorsque l'option Cache Performs Loading of Missing Entries est activée (cache en lecture) :
1. Remplacez le service LoadEntry sur l'objet cache.
2. Récupérez une entrée du cache à l'aide de la clé primaire.
Si l'entrée est introuvable, LoadEntry est automatiquement appelé pour renseigner la valeur.
Exemple d'utilisation du service TimesTwo 
Le service TimesTwo prend un nombre, le multiplie par 2, puis stocke le résultat dans un cache. Pour configurer ceci, procédez comme suit :
1. Créez une forme de données (TimesTwoDataShape) avec les champs suivants : operand: (LONG, primaryKey) et timesTwoValue: (LONG).
2. Créez un objet cache (MyTimesTwoCache) avec TimesTwoDataShape configuré.
3. Ajoutez le service TimesTwo à MyTimesTwoCache :
Entrée : x (un nombre LONG)
Sortie : result (un nombre LONG)
// Input is x as a LONG
// Output is result as LONG
// MyTimesTwoCache CacheThing is configured with a DataShape with two fields:
// operand: (LONG, primaryKey)
// timesTwoValue: (LONG)
result = -1;
// Check the cache first, to see if we have already calculated x*2
// GetEntryByKey is a convenience method that takes the String value the configured DataShape's Primary Key ("key" in this example)
// cacheResult is an InfoTable with the DataShape of the cache
let cacheResult = Things["MyTimesTwoCache"].GetEntryByKey({ operand: x.toString() });
if (cacheResult.getRowCount() === 0) {
// Cache didn't have a result, so calculate it
let timesTwo = x*2;

// Put the result in the cache for the next time we need this multiple
// operand and value are from the Cache's configured DataShape
let cacheInput = getInfoTableForPut(x, timesTwo);
Things["MyTimesTwoCache"].PutEntry({
values: cacheInput
});

// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("PutEntry the following entry into the MyTimesTwoCache: {operand: " + x + ", timesTwoValue: " + timesTwo + "}");

// Set the global result Output variable
result = timesTwo;
} else {
// If results are found, they are always in the first row of the InfoTable
let row = cacheResult.getRow(0);
logger.debug("Found the following entry already in MyTimesTwoCache: {operand: " + row.operand + ", timesTwoValue: " + row.timesTwoValue + "}");
result = row.timesTwoValue;
}
function getInfoTableForPut(operand, timesTwoValue) {
let infoTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: Things["MyTimesTwoCache"].GetDataShape()
});
infoTable.AddRow({"operand": operand, "timesTwoValue ": timesTwoValue });
return infoTable;
}
Exemple : mise en cache d'un wrapper de service 
Cet exemple montre comment mettre en cache manuellement les résultats du service QueryImplementingThingsV2.
1. Créez une forme de données nommée Cached_QueryImplementingThingsV2_DataShape avec les champs suivants :
maxItems: (NUMBER, primaryKey)
nameMask: (STRING, primaryKey)
query: (QUERY, primaryKey)
isSortFirst: (BOOLEAN, primaryKey)
result: (INFOTABLE, DataShape RootEntityListV2)
2. Créez un objet cache nommé Cached_QueryImplementingThingsV2 et affectez-lui la forme de données Cached_QueryImplementingThingsV2_DataShape.
3. Pour observer le comportement d'expiration du cache, configurez un délai ExpirationTime court et définissez une règle ExpirationPolicy autre que Never sur l'objet Cached_ReadThrough_QueryImplementingThingsV2.
4. Créez un service nommé CachingQueryImplementingThingsV2 avec les paramètres suivants :
Entrées
maxItems: (NUMBER, required)
nameMask: (STRING, required)
query: (QUERY, required)
isSortFirst: (BOOLEAN, required)
Sortie result: (INFOTABLE, DataShape RootEntityListV2)
/* 
This Service queries QueryImplementingThingsV2 and caches the results as needed
Service Name: CachingQueryImplementingThingsV2 (Overridden on CacheThing)
Input: values InfoTable with Cached_QueryImplementingThingsV2_DataShape
Cached_QueryImplementingThingsV2_DataShape:
maxItems: NUMBER, Primary Key
nameMask: STRING, Primary Key
query: QUERY, Primary Key
isSortFirst: BOOLEAN, Primary Key
result: INFOTABLE, DataShape RootEntityListV2 (NOT a Primary Key!)
*/
let cacheEntryInfoTable = getCacheEntryInfoTable();
cacheEntryInfoTable.AddRow({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */
});
let getEntryResult = me.GetEntry({values: cacheEntryInfoTable});
if (getEntryResult.getRowCount() === 0) {
// Cache didn't have results, so call QueryImplementingThingsV2
let queryResult = ThingTemplates["GenericThing"].QueryImplementingThingsV2({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */
});

// Add the result to the cache, with the primaryKey parameters used to uniquely identify the query.
let newCacheEntryInfoTable = getCacheEntryInfoTable();
newCacheEntryInfoTable.AddRow({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */,
result: queryResult /* INFOTABLE */
});
me.PutEntry({
values: newCacheEntryInfoTable
});
logger.debug("Entry not found in Cache, retrieved from QueryImplementingThingsV2:" + queryResult.ToJSON());
result = queryResult;
} else {
logger.debug("Found entry from Cache:" + getEntryResult.ToJSON());
let row = getEntryResult.getRow(0);
result = row.result;
}

function getCacheEntryInfoTable() {
return Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "Cached_QueryImplementingThingsV2_DataShape"
});
}
Exemple : mise en cache d'un wrapper de service en tant que cache en lecture 
Cet exemple montre comment mettre automatiquement en cache les résultats du service QueryImplementingThingsV2 à l'aide d'un cache en lecture. Après avoir remplacé le service LoadEntry, vous pouvez utiliser le service GetEntry pour charger automatiquement les résultats de la requête QueryImplementingThingsV2 dans le cache.
1. Créez une forme de données nommée Cached_QueryImplementingThingsV2_DataShape avec les champs suivants :
maxItems: (NUMBER, primaryKey)
nameMask: (STRING, primaryKey)
query: (QUERY, primaryKey)
isSortFirst: (BOOLEAN, primaryKey)
result: (INFOTABLE, DataShape RootEntityListV2)
2. Créez un objet cache nommé Cached_ReadThrough_QueryImplementingThingsV2. Affectez-lui la forme de données Cached_QueryImplementingThingsV2_DataShape et activez l'option Cache Performs Loading of Missing Entries.
3. Pour observer le comportement d'expiration du cache, configurez un délai ExpirationTime court et définissez une règle ExpirationPolicy autre que Never sur l'objet Cached_ReadThrough_QueryImplementingThingsV2.
4. Accédez à l'onglet Services, puis sélectionnez Substituer en regard du service LoadEntry avec l'exemple suivant :
/* 
This Service simply proxies a query to QueryImplementingThingsV2 for Read Through caching
Service Name: LoadEntry (Overridden on CacheThing)
Input: values InfoTable with Cached_QueryImplementingThingsV2_DataShape
Cached_QueryImplementingThingsV2_DataShape:
maxItems: NUMBER, Primary Key
nameMask: STRING, Primary Key
query: QUERY, Primary Key
isSortFirst: BOOLEAN, Primary Key
result: INFOTABLE, DataShape RootEntityListV2 (NOT a Primary Key!)
*/
let queryResult = ThingTemplates["GenericThing"].QueryImplementingThingsV2({
maxItems: values.maxItems /* NUMBER */,
nameMask: values.nameMask /* STRING */,
query: values.query /* QUERY */,
isSortFirst: values.isSortFirst /* BOOLEAN */
});
// Copy the results into a new InfoTable.
// This prevents some internal ThingWorx casting issues with some InfoTables
let resultTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: me.GetDataShape() // Returns Cached_QueryImplementingThingsV2_DataShape
});
resultTable.AddRow({
maxItems: values.maxItems /* NUMBER {"defaultValue":500} */,
nameMask: values.nameMask /* STRING */,
query: values.query /* QUERY */,
isSortFirst: values.isSortFirst /* BOOLEAN */,
result: queryResult
});
let result = resultTable;
Exemple avec requête de table de données 
Cet exemple montre comment utiliser un service BetweenDatesDataTableQuery fonctionnel pour trouver la plus grande valeur d'une table de données entre deux dates et stocker les résultats dans un cache. Les appels uniques à CachingBetweenDatesDataTableQuery interrogeront initialement la table de données de support, mais les appels identiques suivants utiliseront en revanche le cache.
Pour configurer ceci, procédez comme suit :
1. Créez une forme de données (TimeValueDataShape) avec les champs suivants : longKey: (LONG, primaryKey) et dateKey: (DATETIME, primaryKey).
2. Créez une table de données (DemoDataTable) avec la forme de données TimeValueDataShape.
3. Créez une forme de données (TimeSpanValueCacheDataShape) avec les champs suivants : startDate: (DATETIME, primaryKey), endDate: (DATETIME, primaryKey) et longValue: (LONG).
4. Créez un objet de cache (CacheThingDemo) avec la forme de données TimeSpanValueCacheDataShape configurée.
5. Créez les services suivants sur CacheThingDemo :
CachingBetweenDatesDataTableQuery — Entrées : StartDate et EndDate comme DATETIME. Sorties : result comme LONG.
BetweenDatesDataTableQuery — Entrées : StartDate et EndDate comme DATETIME. Sorties : result comme LONG.
* 
Ce service renseigne automatiquement les données de démonstration dans la table de données dans la plage de dates interrogée.
6. Facultatif. Configurez un court délai ExpirationTime avec une autre ExpirationPolicy que Never sur le CacheThingDemo pour observer les entrées expirées du cache.
CachingBetweenDatesDataTableQuery
/* Reads the Cached results of BetweenDatesDataTableQuery Service.
If Cache doesn't have the result, call BetweenDatesDataTableQuery and load results into Cache.

Service Name: CachingBetweenDatesDataTableQuery
Inputs: StartDate[DATETIME, required], EndDate[DATETIME, required]
Output: LONG
*/
// This example uses CacheThing.GetEntry, which requires a one-row infoTable populated with the CacheThing's DataShapes primaryKey getEntryByKey
let cacheEntryInfoTable = getCacheEntryInfoTable();
cacheEntryInfoTable.AddRow({"startDate": StartDate, "endDate": EndDate});
let getEntryResult = Things["CacheThingDemo"].GetEntry({
values: cacheEntryInfoTable
});
if (getEntryResult.getRowCount() === 0) {
// Cache didn't have results, so go to backing DataTable, by calling the BetweenDatesDataTableQuery Service
let queryResult = Things["CacheThingDemo"].BetweenDatesDataTableQuery({
StartDate: StartDate,
EndDate: EndDate
});

// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("PutEntry called for BetweenDatesQueryCache: {StartDate: " + StartDate + ", EndDate: " + EndDate + " value: " + queryResult + "}");
if (!queryResult || queryResult < 0) {
// BetweenDatesDataTableQuery should always populate with demo data if no data is in the StartDate - EndDate range
throw new Error("BetweenDatesDataTableQuery did not return results");
}
let newCacheEntryInfoTable = getCacheEntryInfoTable();
newCacheEntryInfoTable.AddRow({"startDate": StartDate, "endDate": EndDate, "longValue": queryResult});
Things["CacheThingDemo"].PutEntry({
values: newCacheEntryInfoTable
});
result = queryResult;
} else {
let row = getEntryResult.getRow(0);
logger.debug("Found the following entry already in Cache : {StartDate: " + row.startDate + ", EndDate: " + row.endDate + ", LongValue: " + row.longValue + "}");
result = row.longValue;
}
function getCacheEntryInfoTable() {
return Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TimeSpanValueCacheDataShape"
});
}
BetweenDatesDataTableQuery
/*  This service queries a range of dates, based on the dateKey column, and returns the greatest longKey value found.
If there are no entries between StartDate and EndDate this Service dynamically populates demo data into demoDataTable, and returns that result.

Service Name: BetweenDatesDataTableQuery
Inputs: StartDate[DATETIME, required], EndDate[DATETIME, required]
Output: LONG
*/
if (StartDate >= EndDate) {
throw Error("StartDate must be before EndDate");
}
let dataTable = Things["DemoDataTable"];
let queryResult = queryGreatestLongKeyBetweenDates(dataTable, StartDate, EndDate);
if (queryResult.getRowCount() === 0) {
// If we don't get any results, first populate the date range with random values, then retry
// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("No values found between [" + StartDate + "] and [" + EndDate + "], populating 100 demo values and re-querying");
populateDemoDataTable(dataTable, StartDate, EndDate);
// Re-query the now populated DateTable
queryResult = queryGreatestLongKeyBetweenDates(dataTable, StartDate, EndDate);
result = queryResult.getRow(0).get("longKey");
} else {
result = queryResult.getRow(0).get("longKey");
}
// Queries the DataTable for the largest longKey column value between the given dates
// Returns: One-row InfoTable with the found row.
function queryGreatestLongKeyBetweenDates(dateTable, startDate, endDate) {
let greatestBetweenDatesQuery = {
"filters": {
"type": "Between",
"fieldName": "dateKey",
"from": startDate,
"to": endDate
},
"sorts": [{
"fieldName": "longKey",
"isAscending": false
}]
};
// Run the Query to find the greatest Value Between Two Dates
let queryResult = dataTable.QueryDataTableEntries({
maxItems: 1,
query: greatestBetweenDatesQuery,
});

logger.debug("Queried between [" + StartDate + "] and [" + EndDate + "], found:" + queryResult.toJSON());
return queryResult;
}
function populateDemoDataTable(dataTable, startDate, endDate) {
// add 100 random entries between startDate and endDate
for (let entry = 0; entry < 100; entry++) {
let randomTimeBetween = randomDate(startDate, endDate);
let entry = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TimeValueDataShape"
});
entry.AddRow({
"longKey": Math.floor(Math.random() * 1000),
"dateKey": randomTimeBetween
});
Things["DemoDataTable"].AddDataTableEntry({
values: entry /* INFOTABLE */ ,
});
}
}
function randomDate(startDate, endDate) {
let randomTime = Math.random() * (endDate.getTime() - startDate.getTime()) + startDate.getTime();
return new Date(randomTime);
}
Est-ce que cela a été utile ?