21 – H2 TechDB (Nouveaute V4)
Version : 4.0.2 Date : 2026-01-15
1. Introduction
La H2 TechDB est une base de donnees embarquee introduite dans le Socle V4 pour stocker l’etat technique de maniere persistante.
Pourquoi H2 ?
| Critere | H2 | Nitrite (ancien) |
|---|---|---|
| Embarque | ✅ | ✅ |
| ARM/AMD64 | ✅ | ⚠️ Problemes |
| UI debug | ✅ H2 Console | ❌ |
| JSON SQL | ✅ JSON_VALUE | ❌ |
| Stabilite | ✅ | ⚠️ v4 instable |
Nouveautes V4.0.1
- Standard de tables x_ : Nouvelle structure avec champs techniques standardises
- H2 Console sur port 9376 : Interface web dediee pour explorer la base
- TechDbReaderWorker : Worker passif de lecture des donnees
- TechDbPurgeWorker : Purge automatique des donnees obsoletes
Nouveautes V4.0.2
- API SQL REST : Nouveau endpoint
/techdb/querypour requetes SQL via HTTP - Authentification Basic Auth : Securisation de l’acces API
- Rate Limiting : Protection contre les abus (60 req/min/IP par defaut)
- Mode Readonly : Protection contre les modifications accidentelles
2. Cas d’usage
La TechDB stocke :
- Offsets/sequences : Position dans Kafka, NATS, DB2
- Etat local des workers : Statut, derniere execution
- Evenements techniques : Logs importants
- Fallback logs : Logs non envoyes (LogForwarder)
- Cle-valeur : Donnees generiques avec TTL
3. Configuration
3.1 application.yml
socle:
techdb:
enabled: ${TECHDB_ENABLED:true}
url: jdbc:h2:file:${TECHDB_PATH:./data/socle-techdb};MODE=PostgreSQL;DB_CLOSE_DELAY=-1;AUTO_SERVER=TRUE
username: ${TECHDB_USERNAME:LMVI}
password: ${TECHDB_PASSWORD:LMVI-SOCLEV004}
# H2 Console Web (port 9376)
console:
enabled: ${TECHDB_CONSOLE_ENABLED:true}
port: ${TECHDB_CONSOLE_PORT:9376}
bind_address: ${TECHDB_CONSOLE_BIND:}
allow_remote: ${TECHDB_CONSOLE_ALLOW_REMOTE:false}
# Purge automatique des donnees anciennes
purge:
enabled: ${TECHDB_PURGE_ENABLED:true}
schedule: ${TECHDB_PURGE_SCHEDULE:0 0 3 * * ?} # 3h du matin
events_retention_days: ${TECHDB_PURGE_EVENTS_DAYS:7}
logs_retention_days: ${TECHDB_PURGE_LOGS_DAYS:3}
3.2 Variables d’environnement
| Variable | Description | Defaut |
|---|---|---|
TECHDB_ENABLED |
Activer TechDB | true |
TECHDB_PATH |
Chemin fichier H2 | ./data/socle-techdb |
TECHDB_USERNAME |
Nom d’utilisateur | LMVI |
TECHDB_PASSWORD |
Mot de passe | LMVI-SOCLEV004 |
TECHDB_CONSOLE_ENABLED |
Activer console web | true |
TECHDB_CONSOLE_PORT |
Port console | 9376 |
TECHDB_CONSOLE_ALLOW_REMOTE |
Acces distant | false |
TECHDB_PURGE_ENABLED |
Activer purge auto | true |
TECHDB_PURGE_EVENTS_DAYS |
Retention events | 7 |
TECHDB_PURGE_LOGS_DAYS |
Retention logs | 3 |
3.3 Personnalisation des identifiants par environnement
Les identifiants par defaut (LMVI / LMVI-SOCLEV004) conviennent pour le developpement et les tests. Pour la production, il est recommande de personnaliser via variables d’environnement.
Docker Compose :
services:
mon-app:
environment:
- TECHDB_USERNAME=MonUserProd
- TECHDB_PASSWORD=MonMotDePasseSecurise123!
Java direct :
export TECHDB_USERNAME=MonUserProd
export TECHDB_PASSWORD=MonMotDePasseSecurise123!
java -jar mon-application.jar
Kubernetes :
env:
- name: TECHDB_USERNAME
valueFrom:
secretKeyRef:
name: techdb-credentials
key: username
- name: TECHDB_PASSWORD
valueFrom:
secretKeyRef:
name: techdb-credentials
key: password
Note : Si vous changez les identifiants sur une base existante, vous devez supprimer le fichier
socle-techdb.mv.dbet laisser l’application recreer la base.
4. Schéma de base
Les tables sont créées automatiquement au démarrage :
-- Offsets / séquences
CREATE TABLE IF NOT EXISTS socle_offsets (
id IDENTITY PRIMARY KEY,
source_name VARCHAR(200) NOT NULL,
partition_key VARCHAR(200) NOT NULL,
last_sequence BIGINT NOT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
extra JSON,
UNIQUE(source_name, partition_key)
);
-- État local des workers
CREATE TABLE IF NOT EXISTS socle_worker_state (
id IDENTITY PRIMARY KEY,
worker_id VARCHAR(200) NOT NULL UNIQUE,
status VARCHAR(20) NOT NULL,
last_heartbeat TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
metadata JSON
);
-- Événements techniques
CREATE TABLE IF NOT EXISTS socle_events (
id IDENTITY PRIMARY KEY,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
type VARCHAR(100) NOT NULL,
payload JSON
);
-- Fallback logs (LogForwarder)
CREATE TABLE IF NOT EXISTS socle_log_fallback (
id IDENTITY PRIMARY KEY,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
log_entry JSON NOT NULL,
retry_count INT DEFAULT 0
);
5. Interface TechDbManager
package eu.lmvi.socle.techdb;
@Component
public class TechDbManager {
// ===== Lifecycle =====
/**
* Initialise la base H2 et crée les tables
*/
public void initialize();
/**
* Ferme proprement la connexion
*/
public void close();
/**
* Vérifie la santé de la base
*/
public boolean isHealthy();
// ===== Offsets =====
/**
* Sauvegarde un offset
*/
public void saveOffset(String sourceName, String partitionKey,
long sequence, Map<String, Object> extra);
/**
* Récupère un offset
*/
public OptionalLong getOffset(String sourceName, String partitionKey);
/**
* Liste tous les offsets d'une source
*/
public List<OffsetRecord> getOffsets(String sourceName);
// ===== Worker State =====
/**
* Sauvegarde l'état d'un worker
*/
public void saveWorkerState(String workerId, String status,
Map<String, Object> metadata);
/**
* Récupère l'état d'un worker
*/
public Optional<WorkerState> getWorkerState(String workerId);
// ===== Events =====
/**
* Enregistre un événement technique
*/
public void logEvent(String type, Map<String, Object> payload);
/**
* Récupère les événements
*/
public List<TechEvent> getEvents(String type, Instant since, int limit);
// ===== Generic KV =====
public void put(String key, String value);
public Optional<String> get(String key);
public void delete(String key);
}
6. Utilisation
6.1 Injection
@Service
public class MonWorker implements Worker {
@Autowired
private TechDbManager techDb;
@Override
public void doWork() {
// Récupérer le dernier offset
OptionalLong lastOffset = techDb.getOffset("kafka", "my-topic-0");
long startFrom = lastOffset.orElse(0L);
// Traiter les messages...
long newOffset = processMessages(startFrom);
// Sauvegarder le nouvel offset
techDb.saveOffset("kafka", "my-topic-0", newOffset,
Map.of("processed", true));
}
}
6.2 Gestion des offsets
// Sauvegarder
techDb.saveOffset("nats", "events.orders", 123456789L,
Map.of("consumer", "order-processor"));
// Récupérer
OptionalLong offset = techDb.getOffset("nats", "events.orders");
if (offset.isPresent()) {
log.info("Dernier offset: {}", offset.getAsLong());
}
// Lister tous les offsets NATS
List<OffsetRecord> offsets = techDb.getOffsets("nats");
offsets.forEach(o -> log.info("{}: {}", o.partitionKey(), o.lastSequence()));
6.3 État des workers
// Sauvegarder l'état
techDb.saveWorkerState("kafka-consumer-001", "RUNNING",
Map.of(
"lastProcessed", Instant.now(),
"messagesPerMinute", 523
));
// Récupérer l'état
Optional<WorkerState> state = techDb.getWorkerState("kafka-consumer-001");
state.ifPresent(s -> {
log.info("Worker {} - Status: {}", s.workerId(), s.status());
});
6.4 Événements techniques
// Logger un événement
techDb.logEvent("PIPELINE_ERROR", Map.of(
"pipeline", "order-processing",
"error", "Connection timeout",
"messageId", "msg-123"
));
// Récupérer les événements récents
List<TechEvent> errors = techDb.getEvents(
"PIPELINE_ERROR",
Instant.now().minus(1, ChronoUnit.HOURS),
100
);
7. H2 Console Web (Port 9376)
Le Socle V4 expose une console H2 dediee sur le port 9376 via le TechDbConsoleWorker.
Acces
http://localhost:9376
Informations de connexion
| Champ | Valeur |
|---|---|
| JDBC URL | jdbc:h2:./data/socle-techdb (local) ou jdbc:h2:/app/data/socle-techdb (Docker) |
| User | LMVI (defaut, personnalisable via TECHDB_USERNAME) |
| Password | LMVI-SOCLEV004 (defaut, personnalisable via TECHDB_PASSWORD) |
| Driver | org.h2.Driver |
Configuration
socle:
techdb:
console:
enabled: true # Activer/desactiver
port: 9376 # Port dedie
bind_address: "" # Vide = toutes interfaces
allow_remote: false # Securite: localhost only
Requetes utiles
-- Voir tous les offsets
SELECT * FROM techdb_offsets ORDER BY x_dateCreated DESC;
-- Offsets Kafka uniquement
SELECT * FROM techdb_offsets WHERE topic LIKE 'kafka%';
-- Etat des workers
SELECT worker_name, state, last_run_at, error_count FROM techdb_worker_state;
-- Evenements non traites
SELECT * FROM techdb_events WHERE processed = FALSE ORDER BY x_dateCreated;
-- Logs non envoyes
SELECT COUNT(*) as pending FROM techdb_log_buffer WHERE forwarded = FALSE;
-- Cles KV avec expiration
SELECT kv_key, value_type, expires_at FROM techdb_kv WHERE expires_at IS NOT NULL;
8. API SQL REST (Nouveaute V4.0.2)
Le Socle V4 expose une API REST permettant d’executer des requetes SQL sur la TechDB. Cette API est distincte de la console H2 et offre un acces programmatique securise.
8.1 Configuration
socle:
techdb:
sql_api:
enabled: ${TECHDB_SQL_API_ENABLED:false}
auth:
user: ${TECHDB_API_USER:admin}
password: ${TECHDB_API_PASSWORD:}
security:
readonly: ${TECHDB_SQL_API_READONLY:true}
blocked_tables: ${TECHDB_SQL_API_BLOCKED_TABLES:}
limits:
max_rows: ${TECHDB_SQL_API_MAX_ROWS:1000}
timeout_seconds: ${TECHDB_SQL_API_TIMEOUT:30}
rate_limit_per_minute: ${TECHDB_SQL_API_RATE_LIMIT:60}
logging:
log_queries: ${TECHDB_SQL_API_LOG_QUERIES:true}
8.2 Variables d’environnement
| Variable | Description | Defaut |
|---|---|---|
TECHDB_SQL_API_ENABLED |
Activer l’API SQL | false |
TECHDB_API_USER |
Utilisateur Basic Auth | admin |
TECHDB_API_PASSWORD |
Mot de passe (vide = pas d’auth) | « |
TECHDB_SQL_API_READONLY |
Mode lecture seule | true |
TECHDB_SQL_API_BLOCKED_TABLES |
Tables interdites (CSV) | « |
TECHDB_SQL_API_MAX_ROWS |
Limite de lignes | 1000 |
TECHDB_SQL_API_TIMEOUT |
Timeout requetes (sec) | 30 |
TECHDB_SQL_API_RATE_LIMIT |
Requetes/minute/IP | 60 |
8.3 Endpoints
| Methode | Path | Description |
|---|---|---|
| POST | /techdb/query |
Executer une requete SQL |
| GET | /techdb/tables |
Liste des tables |
| GET | /techdb/tables/{name} |
Details d’une table |
| GET | /techdb/stats |
Statistiques DB |
8.4 Authentification
L’API utilise Basic Auth. Si un mot de passe est configure, toutes les requetes doivent inclure l’en-tete:
Authorization: Basic base64(user:password)
Exemple avec curl:
# Sans authentification (si TECHDB_API_PASSWORD vide)
curl http://localhost:8080/techdb/tables
# Avec authentification
curl -u admin:monmotdepasse http://localhost:8080/techdb/query \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT * FROM techdb_kv LIMIT 10"}'
8.5 Executer une requete SQL
Requete:
curl -X POST http://localhost:8080/techdb/query \
-H "Content-Type: application/json" \
-u admin:secret \
-d '{
"sql": "SELECT * FROM techdb_events WHERE event_type = ?",
"params": ["WORKER_START"],
"maxRows": 100
}'
Reponse succes:
{
"success": true,
"timestamp": 1705312800000,
"executionTimeMs": 12,
"rowCount": 15,
"columns": ["X_ID", "X_DATECREATED", "EVENT_TYPE", "SOURCE", "DATAS"],
"rows": [
{"X_ID": 1, "X_DATECREATED": "2025-01-15T10:00:00", "EVENT_TYPE": "WORKER_START", ...},
...
],
"truncated": false
}
Reponse erreur:
{
"success": false,
"timestamp": 1705312800000,
"error": {
"code": "SQL_SYNTAX_ERROR",
"message": "Syntax error in SQL statement"
}
}
8.6 Codes d’erreur
| Code | HTTP Status | Description |
|---|---|---|
SQL_SYNTAX_ERROR |
400 | Erreur de syntaxe SQL |
DDL_NOT_ALLOWED |
403 | Operation DDL interdite |
READONLY_VIOLATION |
403 | Non-SELECT en mode readonly |
TABLE_BLOCKED |
403 | Table bloquee par config |
QUERY_TIMEOUT |
408 | Timeout depasse |
UNAUTHORIZED |
401 | Authentification requise |
RATE_LIMITED |
429 | Limite requetes depassee |
TECHDB_DISABLED |
503 | TechDB non disponible |
8.7 Securite
Operations toujours interdites:
- DDL: DROP, ALTER, CREATE, TRUNCATE, GRANT, REVOKE
- Commandes dangereuses: SHUTDOWN, SCRIPT, BACKUP, RESTORE
Mode readonly (defaut):
- Seuls les SELECT sont autorises
- INSERT, UPDATE, DELETE interdits
Tables bloquees:
socle:
techdb:
sql_api:
security:
blocked_tables: techdb_log_buffer,techdb_kv # CSV
8.8 Rate Limiting
L’API applique un rate limiting par IP (sliding window par minute).
Par defaut: 60 requetes/minute/IP
Depassement = HTTP 429 Too Many Requests
8.9 Metriques Prometheus
techdb_sql_api_queries_total{status="success|error|timeout"}
techdb_sql_api_queries_duration_seconds
techdb_sql_api_auth_failures_total
techdb_sql_api_rate_limited_total
8.10 Exemples pratiques
Lister les tables:
curl http://localhost:8080/techdb/tables
Details d’une table:
curl http://localhost:8080/techdb/tables/TECHDB_EVENTS
Statistiques DB:
curl http://localhost:8080/techdb/stats
Requete avec parametres:
curl -X POST http://localhost:8080/techdb/query \
-H "Content-Type: application/json" \
-d '{
"sql": "SELECT worker_name, state, error_count FROM techdb_worker_state WHERE state = ?",
"params": ["RUNNING"]
}'
9. Workers TechDB
Le Socle V4 inclut 3 workers dedies a la gestion de TechDB:
9.1 TechDbReaderWorker
Worker PASSIVE exposant des methodes de lecture.
@Autowired
private TechDbReaderWorker reader;
// Recuperer tous les offsets
List<Map<String, Object>> offsets = reader.getAllOffsets();
// Recuperer les evenements recents
List<Map<String, Object>> events = reader.getRecentEvents(100);
// Executer une requete personnalisee
List<Map<String, Object>> results = reader.executeCustomQuery(
"SELECT * FROM techdb_worker_state WHERE state = 'RUNNING'"
);
9.2 TechDbPurgeWorker
Worker CRON qui purge automatiquement les donnees obsoletes.
socle:
techdb:
purge:
enabled: true
schedule: "0 0 3 * * ?" # 3h du matin
events_retention_days: 7
logs_retention_days: 3
Donnees purgees :
- Evenements traites > 7 jours
- Logs forwardes > 3 jours
- Cles KV expirees
9.3 TechDbConsoleWorker
Worker PASSIVE qui demarre la console H2 sur le port 9376.
@Autowired
private TechDbConsoleWorker console;
// Verifier si la console est accessible
boolean running = console.isConsoleRunning();
// Obtenir les infos de connexion
Map<String, String> info = console.getConnectionInfo();
10. Fonctions JSON H2
H2 2.x supporte les fonctions JSON SQL standard :
-- Extraction de valeur
SELECT JSON_VALUE('{"name":"John","age":30}', '$.name');
-- Résultat: John
-- Extraction d'objet
SELECT JSON_QUERY('{"data":{"items":[1,2,3]}}', '$.data');
-- Résultat: {"items":[1,2,3]}
-- Test d'existence
SELECT JSON_EXISTS('{"name":"John"}', '$.name');
-- Résultat: TRUE
-- Construction JSON
SELECT JSON_OBJECT('name': 'John', 'age': 30);
-- Résultat: {"name":"John","age":30}
-- Filtrage sur JSON
SELECT * FROM socle_events
WHERE JSON_VALUE(payload, '$.severity') = 'ERROR';
11. Integration avec SharedDataRegistry
TechDB complète SharedDataRegistry :
| Aspect | SharedDataRegistry | TechDbManager |
|---|---|---|
| Scope | Runtime (mémoire) | Persistant (fichier) |
| Survie restart | Non | Oui |
| Performance | Ultra rapide | Rapide |
| Usage | Métriques live | Offsets, état |
Exemple de synergie
@Service
public class MonService {
@Autowired
private TechDbManager techDb;
@Autowired
private SharedDataRegistry sharedData;
public void initialize() {
// Restaurer l'offset depuis TechDB
OptionalLong persisted = techDb.getOffset("kafka", "topic-0");
// Créer le compteur en mémoire
sharedData.createSequence("kafka.offset.topic-0",
persisted.orElse(0L),
HealthLevel.CRITICAL);
}
public void onMessage(long offset) {
// Mettre à jour en mémoire (rapide)
sharedData.setSequence("kafka.offset.topic-0", offset);
// Persister périodiquement (moins fréquent)
if (offset % 1000 == 0) {
techDb.saveOffset("kafka", "topic-0", offset, null);
}
}
}
12. Bonnes pratiques
DO
- ✅ Utiliser TechDB pour les données qui doivent survivre au restart
- ✅ Persister les offsets périodiquement (pas à chaque message)
- ✅ Utiliser JSON pour les métadonnées flexibles
- ✅ Activer H2 Console uniquement en dev
DON’T
- ❌ Stocker des données volumineuses (utiliser PostgreSQL)
- ❌ Faire des requêtes complexes en boucle doWork()
- ❌ Activer H2 Console en production
- ❌ Utiliser pour du cache haute fréquence (utiliser KvBus)
13. Troubleshooting
Base corrompue
# Supprimer et recréer
rm -rf ./data/socle-techdb.*
# Redémarrer l'application
Fichier verrouillé
Database may be already in use: "locked by another process"
Solution : Arrêter l’autre instance ou utiliser AUTO_SERVER=TRUE dans l’URL.
Console H2 inaccessible
- Vérifier
socle.techdb.console.enabled: true - Vérifier que l’application tourne
- Essayer avec le chemin complet du fichier
14. References
- 28-TECHDB-STANDARD – Standard de creation de tables
- 05-WORKERS – Documentation des Workers
- H2 Documentation
- H2 JSON Functions
- 02-ARCHITECTURE
- 07-SHARED-DATA
Socle V004 – TechDB H2

Laisser un commentaire