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 notebook
  • GET /execution/notebook/{notebookId}/results - Obtenir les résultats d'exécution
  • GET /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

  1. Opérations CRUD : Ne chargez pas explicitement - laissez l'auto-chargement gérer cela
  2. Opérations d'Exécution : Chargez toujours le projet avant
  3. Clients Longue Durée : Déchargez les projets une fois terminés pour libérer la mémoire
  4. Gestionnaires de Contexte : Utilisez les with (Python) ou try/finally pour le nettoyage
  5. Conscience Mémoire : Le cache se nettoie automatiquement à 90% de pression mémoire, mais un déchargement explicite est préférable
  6. Cache Partagé : Rappelez-vous que les utilisateurs de l'interface voient le même état du projet que vos opérations API