Skip to content

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 → Browser

Module 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 tests

DDL Generation

HibernateSchemaTools uses Hibernate's Table and Column objects to generate DDL:

  • generateMigrationDDL() — produces both UP and DOWN scripts
  • buildCreateTableDDL() — idempotent with CREATE 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:

FieldDescription
versionSequential number (1, 2, 3...)
statusPENDING → APPLYING → APPLIED (or FAILED)
upScriptDDL to apply the change
downScriptDDL to rollback the change
workspaceIdWhich 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:

ExchangePurpose
metadata-updatesMain inbound exchange
metadata-updates-retryRetry with TTL delay
metadata-updates-dlxDead letter after max retries

Configuration in RabbitMQConfig.java (processor-service).

Key Files

FileLinesPurpose
FlywayMigrationService.java~1065Migration execution, tracking, rollback
HibernateSchemaTools.java~483DDL generation from Hibernate metadata
DynamicSessionFactoryBuilder.java~447Table/column structure building
EntityMetadataConsumer.java~641RabbitMQ message consumer and routing
TaskCompletionProducer.java~187Sends results back to Quarkus

SchemaStack Internal Developer Documentation