Appearance
Processor
The processor is a Spring Boot service that applies schema changes to customer databases. It receives messages from Quarkus via RabbitMQ, generates DDL using Hibernate, and applies migrations using Flyway.
Runs on port 8082.
Why Spring Boot?
Hibernate Reactive (Quarkus) cannot build SessionFactory instances programmatically or generate DDL at runtime. The processor needs classic blocking Hibernate for this, so it runs as a separate Spring Boot service.
Message Flow
Quarkus REST API
│
│ MetadataUpdateMessage via RabbitMQ
▼
EntityMetadataConsumer (@RabbitListener)
│
├── Entity operations (CREATE/UPDATE/DELETE table)
│ └── processEntityMetadataInternal()
│
└── Column operations (ADD/ALTER/DROP column)
└── processColumnMetadata()
│
▼
FlywayMigrationService.applyMigration()
│
├── HibernateSchemaTools.generateMigrationDDL()
│ └── Generates idempotent DDL (CREATE TABLE IF NOT EXISTS, etc.)
│
└── executeRawSQL() via direct JDBC
│
▼
WorkspaceSchemaMigration (tracking record)
│
▼
TaskCompletionProducer.sendSuccess() / sendFailure()
│
│ TaskCompletionMessage via RabbitMQ
▼
Quarkus consumer → SSE → BrowserModule Structure
spring-boot/processor/
├── processor-consumer/ ← RabbitMQ listener (EntityMetadataConsumer)
├── processor-core/ ← DDL generation (HibernateSchemaTools, DynamicSessionFactoryBuilder)
├── processor-service/ ← Spring Boot app, configuration, Resilience4j
└── processor-test/ ← Integration testsDDL Generation
HibernateSchemaTools uses Hibernate's Table and Column objects to generate DDL:
generateMigrationDDL()— produces both UP and DOWN scriptsbuildCreateTableDDL()— idempotent withCREATE TABLE IF NOT EXISTS- Supports adding/dropping columns, foreign keys, type changes
- Dialect-aware: generates correct SQL for PostgreSQL, MySQL, and SQL Server
DynamicSessionFactoryBuilder creates Hibernate Table structures from metadata DTOs, including foreign key extraction for relationships.
Migration Tracking
Each migration is tracked in the workspace_schema_migration table via the WorkspaceSchemaMigration entity:
| Field | Description |
|---|---|
version | Sequential number (1, 2, 3...) |
status | PENDING → APPLYING → APPLIED (or FAILED) |
upScript | DDL to apply the change |
downScript | DDL to rollback the change |
workspaceId | Which workspace this belongs to |
Migrations are idempotent — duplicate key errors from race conditions are handled gracefully.
Rollback is supported via FlywayMigrationService.rollbackMigration() which executes the stored DOWN script.
Database Connectivity
The processor connects to two types of databases:
Metadata database (dynamicdb) — reads workspace configuration, stores migration tracking. Configured via spring.datasource.* properties.
Customer databases (per workspace) — applies DDL migrations. Connection details are read from workspace_database_config in the metadata database. Credentials are encrypted at rest and decrypted at runtime via EncryptionUtil.
Dead Letter & Retry
RabbitMQ is configured with retry and dead letter exchanges for the processor:
| Exchange | Purpose |
|---|---|
metadata-updates | Main inbound exchange |
metadata-updates-retry | Retry with TTL delay |
metadata-updates-dlx | Dead letter after max retries |
Configuration in RabbitMQConfig.java (processor-service).
Key Files
| File | Lines | Purpose |
|---|---|---|
FlywayMigrationService.java | ~1065 | Migration execution, tracking, rollback |
HibernateSchemaTools.java | ~483 | DDL generation from Hibernate metadata |
DynamicSessionFactoryBuilder.java | ~447 | Table/column structure building |
EntityMetadataConsumer.java | ~641 | RabbitMQ message consumer and routing |
TaskCompletionProducer.java | ~187 | Sends results back to Quarkus |