Cache de Projet
L'API Project Cache gère le chargement en mémoire des projets pour les opérations API. Comprendre quand les projets doivent être chargés est essentiel pour une utilisation efficace de l'API.
Concepts Clés
Architecture de Cache Unifiée
L'API et l'interface utilisateur partagent le même cache en mémoire. Lorsque vous chargez un projet via l'API, c'est le même cache utilisé par l'interface utilisateur. Cela signifie :
- État Partagé : Les opérations API voient les mêmes données que les utilisateurs de l'interface
- Résultats Partagés : Les résultats d'exécution sont visibles à la fois par l'API et l'interface utilisateur
- Pas de Divergence : Il est impossible que l'API et l'interface aient une vue différente d'un projet
Catégories d'Opérations
Les opérations API se répartissent en trois catégories avec des exigences de cache différentes :
| Catégorie | Description | Chargement du Projet Requis ? | Exemples |
|---|---|---|---|
| DB Directe | Opérations en lecture seule | Non | Endpoints GET, gestion locataire/utilisateur |
| Auto-Chargement | Opérations de modification | Non (auto-chargement) | POST/PUT/DELETE sur investigations, notebooks, blocs |
| Chargement Requis | Opérations d'exécution | Oui | Exécution de notebook, récupération des résultats d'exécution |
Modèle Auto-Chargement (Flux Simplifié)
Pour la plupart des opérations CRUD, vous n'avez pas besoin de charger explicitement le projet. L'API charge automatiquement le projet lorsque nécessaire :
# Ancien flux (plus besoin pour CRUD):
# manager.load_project(project_id) # Pas nécessaire !
# Nouveau flux - appelez simplement l'opération directement :
response = requests.put(
f"{BASE_URL}/api/{TENANT_ID}/{PROJECT_ID}/notebook/{notebook_id}",
json={"Name": "Updated Name"},
headers=headers
)
# Le projet se charge automatiquement si besoin
Quand le Chargement Explicite EST Requis
Le chargement explicite du projet est toujours nécessaire pour les opérations d'exécution :
POST /execution/notebook/{notebookId}- Exécuter un notebookGET /execution/notebook/{notebookId}/results- Obtenir les résultats d'exécutionGET /execution/status/{notebookId}- Vérifier le statut d'exécution
Charger un Projet dans le Cache
GET /api/{tenantId}/project/{projectId}/load
Charge un projet dans le cache partagé. Utilisez ceci avant d'exécuter des notebooks.
Paramètres de Chemin
| Paramètre | Type | Requis | Description |
|---|---|---|---|
tenantId |
GUID | Oui | Identifiant du locataire |
projectId |
GUID | Oui | Identifiant du projet |
Réponse (200 OK)
{
"projectId": "87654321-4321-4321-4321-210987654321",
"projectName": "Purchase Order Analysis",
"tenantName": "acme-corp",
"investigationCount": 5,
"notebookCount": 12,
"datasetCount": 3,
"loadedFromCache": false,
"message": "Project loaded from database"
}
Champs de la Réponse
| Champ | Type | Description |
|---|---|---|
projectId |
GUID | Identifiant du projet |
projectName |
string | Nom du projet |
tenantName |
string | Nom du locataire |
investigationCount |
integer | Nombre d'investigations |
notebookCount |
integer | Nombre de notebooks |
datasetCount |
integer | Nombre de jeux de données |
loadedFromCache |
boolean | Vrai si déjà en cache, faux si chargé depuis la base |
message |
string | Message d'état lisible par l'humain |
Comportement du Cache
| Scénario | Réponse | Performance |
|---|---|---|
| Premier appel (absence de cache) | loadedFromCache: false |
~1000ms (requête base de données) |
| Appels suivants (cache hit) | loadedFromCache: true |
~75ms (13x plus rapide) |
| Après 30 min d'inactivité | Expiration du cache | Le prochain appel recharge |
Propriétés du Cache
- Durée : 30 minutes après le dernier accès
- Actualisation automatique : Toute requête API vers le projet remet à zéro la minuterie de 30 minutes
- Partagé : Même cache utilisé par l'interface et l'API
- Gestion mémoire : Nettoyage automatique à 90% d'usage mémoire
Décharger un Projet du Cache
DELETE /api/{tenantId}/project/{projectId}/unload
Supprime un projet du cache, libérant de la mémoire.
Paramètres de Chemin
| Paramètre | Type | Requis | Description |
|---|---|---|---|
tenantId |
GUID | Oui | Identifiant du locataire |
projectId |
GUID | Oui | Identifiant du projet |
Réponse (200 OK)
{
"projectId": "87654321-4321-4321-4321-210987654321",
"wasInCache": true,
"message": "Project unloaded from cache successfully"
}
Exemples de Flux de Travail
Flux de Travail A : Opérations CRUD (Auto-Chargement)
Pour créer, mettre à jour, ou supprimer des investigations, notebooks, ou blocs :
import requests
headers = {"Authorization": f"Bearer {API_KEY}"}
# Appelez simplement l'opération directement - pas besoin de charger !
response = requests.post(
f"{BASE_URL}/api/{TENANT_ID}/{PROJECT_ID}/investigation",
json={"name": "New Investigation", "description": "Created via API"},
headers=headers
)
# Le projet se charge automatiquement si besoin
Flux de Travail B : Exécution de Notebook (Chargement Requis)
Pour exécuter des notebooks et récupérer les résultats :
import requests
import time
headers = {"Authorization": f"Bearer {API_KEY}"}
# Étape 1 : Charger le projet (OBLIGATOIRE pour exécution)
response = requests.get(
f"{BASE_URL}/api/{TENANT_ID}/project/{PROJECT_ID}/load",
headers=headers
)
print(f"Projet chargé : {response.json()['projectName']}")
# Étape 2 : Exécuter le notebook
response = requests.post(
f"{BASE_URL}/api/{TENANT_ID}/{PROJECT_ID}/execution/notebook/{NOTEBOOK_ID}",
headers=headers
)
print(f"Exécution en attente : {response.json()['status']}")
# Étape 3 : Polling jusqu'à la fin
while True:
response = requests.get(
f"{BASE_URL}/api/{TENANT_ID}/{PROJECT_ID}/execution/status/{NOTEBOOK_ID}",
headers=headers
)
status = response.json()
print(f"Statut : {status['status']} ({status['progress']}%)")
if status['status'] == 'Completed':
break
time.sleep(2)
# Étape 4 : Récupérer les résultats
response = requests.get(
f"{BASE_URL}/api/{TENANT_ID}/{PROJECT_ID}/execution/notebook/{NOTEBOOK_ID}/results",
headers=headers
)
results = response.json()
# Étape 5 : Décharger le projet (nettoyage optionnel)
requests.delete(
f"{BASE_URL}/api/{TENANT_ID}/project/{PROJECT_ID}/unload",
headers=headers
)
Exemples d’Implémentation
cURL
# Charger un projet dans le cache
curl -X GET "https://your-mindzie-instance.com/api/12345678-1234-1234-1234-123456789012/project/87654321-4321-4321-4321-210987654321/load" \
-H "Authorization: Bearer YOUR_API_KEY"
# Décharger un projet du cache
curl -X DELETE "https://your-mindzie-instance.com/api/12345678-1234-1234-1234-123456789012/project/87654321-4321-4321-4321-210987654321/unload" \
-H "Authorization: Bearer YOUR_API_KEY"
Python
import requests
TENANT_ID = '12345678-1234-1234-1234-123456789012'
BASE_URL = 'https://your-mindzie-instance.com'
class ProjectCacheManager:
def __init__(self, token):
self.headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
self.loaded_projects = set()
def load_project(self, project_id):
"""Charger un projet dans le cache (requis pour les opérations d'exécution)."""
url = f'{BASE_URL}/api/{TENANT_ID}/project/{project_id}/load'
response = requests.get(url, headers=self.headers)
response.raise_for_status()
result = response.json()
self.loaded_projects.add(project_id)
status = "depuis le cache" if result['loadedFromCache'] else "depuis la base de données"
print(f"Projet '{result['projectName']}' chargé {status}")
return result
def unload_project(self, project_id):
"""Décharger un projet du cache."""
url = f'{BASE_URL}/api/{TENANT_ID}/project/{project_id}/unload'
response = requests.delete(url, headers=self.headers)
response.raise_for_status()
self.loaded_projects.discard(project_id)
return response.json()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
for project_id in list(self.loaded_projects):
self.unload_project(project_id)
# Utilisation avec gestionnaire de contexte
with ProjectCacheManager('your-api-key') as cache:
result = cache.load_project('87654321-4321-4321-4321-210987654321')
# Exécuter les notebooks ici...
# Les projets sont déchargés automatiquement à la sortie
JavaScript/Node.js
const TENANT_ID = '12345678-1234-1234-1234-123456789012';
const BASE_URL = 'https://your-mindzie-instance.com';
class ProjectCacheManager {
constructor(token) {
this.headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
this.loadedProjects = new Set();
}
async loadProject(projectId) {
const url = `${BASE_URL}/api/${TENANT_ID}/project/${projectId}/load`;
const response = await fetch(url, { headers: this.headers });
if (!response.ok) throw new Error(`Échec : ${response.status}`);
const result = await response.json();
this.loadedProjects.add(projectId);
console.log(`Chargé : ${result.projectName} (depuis le cache : ${result.loadedFromCache})`);
return result;
}
async unloadProject(projectId) {
const url = `${BASE_URL}/api/${TENANT_ID}/project/${projectId}/unload`;
const response = await fetch(url, {
method: 'DELETE',
headers: this.headers
});
this.loadedProjects.delete(projectId);
return response.json();
}
async unloadAll() {
await Promise.all(
Array.from(this.loadedProjects).map(id => this.unloadProject(id))
);
}
}
// Utilisation
const cache = new ProjectCacheManager('your-api-key');
try {
await cache.loadProject('87654321-4321-4321-4321-210987654321');
// Exécuter les notebooks ici...
} finally {
await cache.unloadAll();
}
Bonnes Pratiques
- Opérations CRUD : Ne chargez pas explicitement - laissez l'auto-chargement gérer cela
- Opérations d'Exécution : Chargez toujours le projet avant
- Clients Longue Durée : Déchargez les projets une fois terminés pour libérer la mémoire
- Gestionnaires de Contexte : Utilisez les
with(Python) ou try/finally pour le nettoyage - Conscience Mémoire : Le cache se nettoie automatiquement à 90% de pression mémoire, mais un déchargement explicite est préférable
- Cache Partagé : Rappelez-vous que les utilisateurs de l'interface voient le même état du projet que vos opérations API