Database Schema Migration
|
Preview — This feature is functional and tested, but backward compatibility is not guaranteed across releases. |
Quarkus Flow has two schema-bearing modules: JPA persistence and the Quartz scheduler.
Both can create their tables automatically for development (Hibernate ORM’s update mode, or Quartz’s own bundled DDL),
but neither is a safe, versioned migration path for production.
Schema changes need to be reviewed, tied to a Quarkus Flow release, and applied without racing across replicas.
quarkus-flow-db-migration and quarkus-flow-db-migration-quartz package versioned Flyway scripts for each of these schemas.
They are independent, optional extensions, add either one on its own, both, or neither.
Avoiding collisions with your own Flyway migrations
Neither extension requires anything from your application,
each one simply packages its versioned SQL scripts onto the classpath, one subdirectory per supported db-kind (quarkus-flow-db-migration under db/flow-migration/runtime/<db-kind>, quarkus-flow-db-migration-quartz under db/flow-migration/quartz/<db-kind>).
You could point your application’s own default Flyway configuration at one of these locations, and it would run the scripts, but it would then share your application’s Flyway history table and scanned location with them, any overlap in version numbers or table names between your own migrations and the extension’s becomes something you have to manage yourself.
To avoid that, you can instead give the extension’s migrations their own named Flyway configuration and, since Quarkus Flyway ties a named configuration to an identically-named datasource, a named datasource to go with it, pointed at the same physical database as your default one.
That’s what the setup below uses: flow-runtime for quarkus-flow-db-migration, flow-quartz for quarkus-flow-db-migration-quartz, each with its own history table (flyway_flow_runtime_history, flyway_flow_quartz_history) and migration location,
so neither can collide with whatever Flyway setup your own application already has.
If you do set up the named datasource, point it at the same JDBC URL (and typically the same or a DDL-scoped user) as your default datasource; nothing in the extension verifies the two agree, so a misconfigured named datasource would silently migrate a different database than the one your JPA entities actually connect to.
quarkus-flow-db-migration
Ships the JPA runtime persistence schema (workflow_instance_entity, cloud_event_entity, task_info_entity, hash_mapping_info_entity, task_metadata_entity, workflow_metadata_entity) as versioned Flyway scripts, one per supported database (H2, PostgreSQL, MySQL, Oracle, MSSQL).
<dependency>
<groupId>io.quarkiverse.flow</groupId>
<artifactId>quarkus-flow-db-migration</artifactId>
<version>${project.version}</version>
</dependency>
quarkus.hibernate-orm.schema-management.strategy=validate
quarkus.hibernate-orm.physical-naming-strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy
# Default datasource
quarkus.datasource.db-kind=postgresql
quarkus.datasource.jdbc.url=jdbc:postgresql://<host>/<database>
quarkus.datasource.username=<user>
quarkus.datasource.password=<password>
# Named "flow-runtime" datasource - an isolated Flyway migration history/location only,
# not a separate persistence unit. Reusing the default datasource's own connection
# properties here (rather than retyping literal values) keeps the two from drifting apart,
# since nothing checks that they still point at the same physical database.
quarkus.datasource.flow-runtime.db-kind=postgresql
quarkus.datasource.flow-runtime.jdbc.url=${quarkus.datasource.jdbc.url}
quarkus.datasource.flow-runtime.username=${quarkus.datasource.username}
quarkus.datasource.flow-runtime.password=${quarkus.datasource.password}
quarkus.flyway.flow-runtime.table=flyway_flow_runtime_history
quarkus.flyway.flow-runtime.migrate-at-start=true
quarkus.flyway.flow-runtime.locations=db/flow-migration/runtime/postgresql
Replace postgresql in the datasource db-kind and the Flyway locations path with your target database: h2, mysql, oracle, or mssql.
The locations path is deliberately off Flyway’s default db/migration scan root so it won’t collide with any migration scripts your own application ships.
JPA entities still use the default persistence unit
flow-runtime exists only to give this extension’s Flyway migration its own isolated history/location;
it is not a separate Hibernate ORM persistence unit, and quarkus-flow-jpa has no awareness of it.
quarkus-flow-jpa always maps its entities into the Hibernate ORM default persistence unit,
on your application’s default datasource, which is why flow-runtime must point at the same physical database,
per the previous section.
The one extra consequence specific to JPA: quarkus.hibernate-orm.schema-management.strategy on the default persistence unit (not a flow-runtime one) must stay none or validate, never update/drop-and-create, so Hibernate ORM doesn’t race Flyway’s migration - and the migration must run before that validation happens, which Quarkus’s Flyway-before-Hibernate-validate startup ordering already guarantees for migrate-at-start=true.
quarkus-flow-db-migration-quartz
Ships the QRTZ_* schema Quarkus Quartz’s jdbc-cmt/jdbc-tx store types need, through its own isolated flow-quartz named datasource and Flyway configuration.
See Quartz workflow scheduler for the full setup.
Unlike quarkus-flow-db-migration, this extension ships only one db-kind subdirectory today, postgresql (its script relies on that database’s BOOL and BYTEA column types) - more may be added later, following the same per-db-kind layout quarkus-flow-db-migration already uses.
Manual migration
If you’d rather manage the migration yourself instead of using quarkus-flow-db-migration, add the Flyway extension (and the matching database support artifact, if required for your database):
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-flyway</artifactId>
</dependency>
Enable migration at startup and disable Hibernate ORM schema generation in your application.properties:
quarkus.hibernate-orm.schema-management.strategy=none
quarkus.hibernate-orm.physical-naming-strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy
quarkus.flyway.enabled=true
quarkus.flyway.migrate-at-start=true
Then create a migration script at src/main/resources/db/migration/ (e.g. V1__create_tables.sql) with the six tables required by the JPA provider (workflow_instance_entity, cloud_event_entity, task_info_entity, hash_mapping_info_entity, task_metadata_entity, workflow_metadata_entity). Use the complete script that matches your target database below, as-is — these are `quarkus-flow-db-migration’s own scripts, included straight from the extension’s source so they can’t drift from what it actually ships:
CREATE TABLE cloud_event_entity
(
id VARCHAR(255) NOT NULL,
reg_id VARCHAR(255) NOT NULL,
source VARCHAR(255) NOT NULL,
type VARCHAR(255) NOT NULL,
subject VARCHAR(255),
data_content_type VARCHAR(255),
data_schema VARCHAR(255),
time TIMESTAMP(6) WITH TIME ZONE,
data BLOB,
extensions BLOB,
processed_flag BOOLEAN DEFAULT FALSE,
version TINYINT NOT NULL CHECK (version BETWEEN 0 AND 1),
PRIMARY KEY (id)
);
CREATE TABLE workflow_instance_entity
(
application_id VARCHAR(63) NOT NULL,
instance_id VARCHAR(26) NOT NULL,
workflow_name VARCHAR(255) NOT NULL,
workflow_namespace VARCHAR(255) NOT NULL,
workflow_version VARCHAR(255) NOT NULL,
started_at TIMESTAMP(6) WITH TIME ZONE NOT NULL,
status TINYINT CHECK (status BETWEEN 0 AND 6),
input VARBINARY,
PRIMARY KEY (application_id, instance_id)
);
CREATE TABLE task_info_entity
(
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(26) NOT NULL,
json_pointer VARCHAR(679) NOT NULL,
iteration INTEGER NOT NULL,
task_type INTEGER NOT NULL CHECK (task_type IN (1, 2)),
is_end_node BOOLEAN,
retry_attempt INTEGER,
instant TIMESTAMP(6) WITH TIME ZONE,
next_position VARCHAR(255),
context VARBINARY,
model VARBINARY,
context_hash_key VARBINARY,
context_hash_index VARBINARY,
model_hash_key VARBINARY,
model_hash_index VARBINARY,
PRIMARY KEY (iteration, application_id, json_pointer, workflow_instance_id),
CHECK (task_type <> 1 OR (is_end_node IS NOT NULL)),
CHECK (task_type <> 2 OR (retry_attempt IS NOT NULL)),
CONSTRAINT fk_task_workflow_instance
FOREIGN KEY (application_id, workflow_instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE hash_mapping_info_entity
(
id VARCHAR(255) NOT NULL,
instance VARCHAR(255),
"key" VARBINARY,
data BLOB,
PRIMARY KEY (id)
);
CREATE INDEX hashKey_idx ON hash_mapping_info_entity ("key");
CREATE INDEX instance_idx ON hash_mapping_info_entity (instance);
CREATE TABLE task_metadata_entity
(
meta_name VARCHAR(128) NOT NULL,
iteration INTEGER NOT NULL,
json_pointer VARCHAR(679) NOT NULL,
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(26) NOT NULL,
hash_key VARBINARY,
hash_index VARBINARY,
raw_value VARBINARY,
PRIMARY KEY (meta_name, iteration, json_pointer, application_id, workflow_instance_id),
CONSTRAINT fk_task_metadata_task
FOREIGN KEY (iteration, application_id, json_pointer, workflow_instance_id)
REFERENCES task_info_entity (iteration, application_id, json_pointer, workflow_instance_id)
ON DELETE CASCADE
);
CREATE TABLE workflow_metadata_entity
(
meta_name VARCHAR(128) NOT NULL,
instance_id VARCHAR(26) NOT NULL,
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(255),
hash_key VARBINARY,
hash_index VARBINARY,
raw_value VARBINARY,
PRIMARY KEY (meta_name, instance_id, application_id),
CONSTRAINT fk_workflow_metadata_workflow
FOREIGN KEY (application_id, instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE cloud_event_entity
(
id VARCHAR(255) NOT NULL,
reg_id VARCHAR(255) NOT NULL,
source VARCHAR(255) NOT NULL,
type VARCHAR(255) NOT NULL,
subject VARCHAR(255),
data_content_type VARCHAR(255),
data_schema VARCHAR(255),
`time` DATETIME(6),
data LONGBLOB,
extensions LONGBLOB,
processed_flag BOOLEAN DEFAULT FALSE,
version TINYINT NOT NULL CHECK (version BETWEEN 0 AND 1),
PRIMARY KEY (id)
);
CREATE TABLE workflow_instance_entity
(
application_id VARCHAR(63) CHARACTER SET ascii NOT NULL,
instance_id VARCHAR(26) CHARACTER SET ascii NOT NULL,
workflow_name VARCHAR(255) NOT NULL,
workflow_namespace VARCHAR(255) NOT NULL,
workflow_version VARCHAR(255) NOT NULL,
started_at DATETIME(6) NOT NULL,
status TINYINT CHECK (status BETWEEN 0 AND 6),
input LONGBLOB,
PRIMARY KEY (application_id, instance_id)
);
CREATE TABLE task_info_entity
(
application_id VARCHAR(63) CHARACTER SET ascii NOT NULL,
workflow_instance_id VARCHAR(26) CHARACTER SET ascii NOT NULL,
json_pointer VARCHAR(679) CHARACTER SET ascii NOT NULL,
iteration INTEGER NOT NULL,
task_type INTEGER NOT NULL CHECK (task_type IN (1, 2)),
is_end_node BOOLEAN,
retry_attempt INTEGER,
instant DATETIME(6),
next_position VARCHAR(255),
context LONGBLOB,
model LONGBLOB,
context_hash_key LONGBLOB,
context_hash_index LONGBLOB,
model_hash_key LONGBLOB,
model_hash_index LONGBLOB,
PRIMARY KEY (iteration, application_id, json_pointer, workflow_instance_id),
CHECK (task_type <> 1 OR (is_end_node IS NOT NULL)),
CHECK (task_type <> 2 OR (retry_attempt IS NOT NULL)),
CONSTRAINT fk_task_workflow_instance
FOREIGN KEY (application_id, workflow_instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE hash_mapping_info_entity
(
id VARCHAR(255) NOT NULL,
instance VARCHAR(255),
`key` VARBINARY(255),
data LONGBLOB,
PRIMARY KEY (id)
);
CREATE INDEX hashKey_idx ON hash_mapping_info_entity (`key`);
CREATE INDEX instance_idx ON hash_mapping_info_entity (instance);
CREATE TABLE task_metadata_entity
(
meta_name VARCHAR(128) CHARACTER SET ascii NOT NULL,
iteration INTEGER NOT NULL,
json_pointer VARCHAR(679) CHARACTER SET ascii NOT NULL,
application_id VARCHAR(63) CHARACTER SET ascii NOT NULL,
workflow_instance_id VARCHAR(26) CHARACTER SET ascii NOT NULL,
hash_key LONGBLOB,
hash_index LONGBLOB,
raw_value LONGBLOB,
PRIMARY KEY (meta_name, iteration, json_pointer, application_id, workflow_instance_id),
CONSTRAINT fk_task_metadata_task
FOREIGN KEY (iteration, application_id, json_pointer, workflow_instance_id)
REFERENCES task_info_entity (iteration, application_id, json_pointer, workflow_instance_id)
ON DELETE CASCADE
);
CREATE TABLE workflow_metadata_entity
(
meta_name VARCHAR(128) CHARACTER SET ascii NOT NULL,
instance_id VARCHAR(26) CHARACTER SET ascii NOT NULL,
application_id VARCHAR(63) CHARACTER SET ascii NOT NULL,
workflow_instance_id VARCHAR(255) CHARACTER SET ascii,
hash_key LONGBLOB,
hash_index LONGBLOB,
raw_value LONGBLOB,
PRIMARY KEY (meta_name, instance_id, application_id),
CONSTRAINT fk_workflow_metadata_workflow
FOREIGN KEY (application_id, instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE cloud_event_entity
(
id VARCHAR(255) NOT NULL,
reg_id VARCHAR(255) NOT NULL,
source VARCHAR(255) NOT NULL,
type VARCHAR(255) NOT NULL,
subject VARCHAR(255),
data_content_type VARCHAR(255),
data_schema VARCHAR(255),
time TIMESTAMP(6) WITH TIME ZONE,
data BYTEA,
extensions BYTEA,
processed_flag BOOLEAN DEFAULT FALSE,
version SMALLINT NOT NULL CHECK (version BETWEEN 0 AND 1),
PRIMARY KEY (id)
);
CREATE TABLE workflow_instance_entity
(
application_id VARCHAR(63) NOT NULL,
instance_id VARCHAR(26) NOT NULL,
workflow_name VARCHAR(255) NOT NULL,
workflow_namespace VARCHAR(255) NOT NULL,
workflow_version VARCHAR(255) NOT NULL,
started_at TIMESTAMP(6) WITH TIME ZONE NOT NULL,
status SMALLINT CHECK (status BETWEEN 0 AND 6),
input BYTEA,
PRIMARY KEY (application_id, instance_id)
);
CREATE TABLE task_info_entity
(
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(26) NOT NULL,
json_pointer VARCHAR(679) NOT NULL,
iteration INTEGER NOT NULL,
task_type INTEGER NOT NULL CHECK (task_type IN (1, 2)),
is_end_node BOOLEAN,
retry_attempt INTEGER,
instant TIMESTAMP(6) WITH TIME ZONE,
next_position VARCHAR(255),
context BYTEA,
model BYTEA,
context_hash_key BYTEA,
context_hash_index BYTEA,
model_hash_key BYTEA,
model_hash_index BYTEA,
PRIMARY KEY (iteration, application_id, json_pointer, workflow_instance_id),
CHECK (task_type <> 1 OR (is_end_node IS NOT NULL)),
CHECK (task_type <> 2 OR (retry_attempt IS NOT NULL)),
CONSTRAINT fk_task_workflow_instance
FOREIGN KEY (application_id, workflow_instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE hash_mapping_info_entity
(
id VARCHAR(255) NOT NULL,
instance VARCHAR(255),
key BYTEA,
data BYTEA,
PRIMARY KEY (id)
);
CREATE INDEX hashKey_idx ON hash_mapping_info_entity (key);
CREATE INDEX instance_idx ON hash_mapping_info_entity (instance);
CREATE TABLE task_metadata_entity
(
meta_name VARCHAR(128) NOT NULL,
iteration INTEGER NOT NULL,
json_pointer VARCHAR(679) NOT NULL,
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(26) NOT NULL,
hash_key BYTEA,
hash_index BYTEA,
raw_value BYTEA,
PRIMARY KEY (meta_name, iteration, json_pointer, application_id, workflow_instance_id),
CONSTRAINT fk_task_metadata_task
FOREIGN KEY (iteration, application_id, json_pointer, workflow_instance_id)
REFERENCES task_info_entity (iteration, application_id, json_pointer, workflow_instance_id)
ON DELETE CASCADE
);
CREATE TABLE workflow_metadata_entity
(
meta_name VARCHAR(128) NOT NULL,
instance_id VARCHAR(26) NOT NULL,
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(255),
hash_key BYTEA,
hash_index BYTEA,
raw_value BYTEA,
PRIMARY KEY (meta_name, instance_id, application_id),
CONSTRAINT fk_workflow_metadata_workflow
FOREIGN KEY (application_id, instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE cloud_event_entity
(
id VARCHAR2(255) NOT NULL,
reg_id VARCHAR2(255) NOT NULL,
source VARCHAR2(255) NOT NULL,
type VARCHAR2(255) NOT NULL,
subject VARCHAR2(255),
data_content_type VARCHAR2(255),
data_schema VARCHAR2(255),
time TIMESTAMP(6) WITH TIME ZONE,
data BLOB,
extensions BLOB,
processed_flag NUMBER(1, 0) DEFAULT 0,
version NUMBER(3, 0) NOT NULL CHECK (version BETWEEN 0 AND 1),
PRIMARY KEY (id)
);
CREATE TABLE workflow_instance_entity
(
application_id VARCHAR2(63) NOT NULL,
instance_id VARCHAR2(26) NOT NULL,
workflow_name VARCHAR2(255) NOT NULL,
workflow_namespace VARCHAR2(255) NOT NULL,
workflow_version VARCHAR2(255) NOT NULL,
started_at TIMESTAMP(6) WITH TIME ZONE NOT NULL,
status NUMBER(3, 0) CHECK (status BETWEEN 0 AND 6),
input RAW(255),
PRIMARY KEY (application_id, instance_id)
);
CREATE TABLE task_info_entity
(
application_id VARCHAR2(63) NOT NULL,
workflow_instance_id VARCHAR2(26) NOT NULL,
json_pointer VARCHAR2(679) NOT NULL,
iteration NUMBER(10, 0) NOT NULL,
task_type NUMBER(10, 0) NOT NULL CHECK (task_type IN (1, 2)),
is_end_node NUMBER(1, 0),
retry_attempt NUMBER(10, 0),
instant TIMESTAMP(6) WITH TIME ZONE,
next_position VARCHAR2(255),
context RAW(255),
model RAW(255),
context_hash_key RAW(255),
context_hash_index RAW(255),
model_hash_key RAW(255),
model_hash_index RAW(255),
PRIMARY KEY (iteration, application_id, json_pointer, workflow_instance_id),
CHECK (task_type <> 1 OR (is_end_node IS NOT NULL)),
CHECK (task_type <> 2 OR (retry_attempt IS NOT NULL)),
CONSTRAINT fk_task_workflow_instance
FOREIGN KEY (application_id, workflow_instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE hash_mapping_info_entity
(
id VARCHAR2(255) NOT NULL,
instance VARCHAR2(255),
key RAW(255),
data BLOB,
PRIMARY KEY (id)
);
CREATE INDEX hashKey_idx ON hash_mapping_info_entity (key);
CREATE INDEX instance_idx ON hash_mapping_info_entity (instance);
CREATE TABLE task_metadata_entity
(
meta_name VARCHAR2(128) NOT NULL,
iteration NUMBER(10, 0) NOT NULL,
json_pointer VARCHAR2(679) NOT NULL,
application_id VARCHAR2(63) NOT NULL,
workflow_instance_id VARCHAR2(26) NOT NULL,
hash_key RAW(255),
hash_index RAW(255),
raw_value RAW(255),
PRIMARY KEY (meta_name, iteration, json_pointer, application_id, workflow_instance_id),
CONSTRAINT fk_task_metadata_task
FOREIGN KEY (iteration, application_id, json_pointer, workflow_instance_id)
REFERENCES task_info_entity (iteration, application_id, json_pointer, workflow_instance_id)
ON DELETE CASCADE
);
CREATE TABLE workflow_metadata_entity
(
meta_name VARCHAR2(128) NOT NULL,
instance_id VARCHAR2(26) NOT NULL,
application_id VARCHAR2(63) NOT NULL,
workflow_instance_id VARCHAR2(255),
hash_key RAW(255),
hash_index RAW(255),
raw_value RAW(255),
PRIMARY KEY (meta_name, instance_id, application_id),
CONSTRAINT fk_workflow_metadata_workflow
FOREIGN KEY (application_id, instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE cloud_event_entity
(
id VARCHAR(255) NOT NULL,
reg_id VARCHAR(255) NOT NULL,
source VARCHAR(255) NOT NULL,
type VARCHAR(255) NOT NULL,
subject VARCHAR(255),
data_content_type VARCHAR(255),
data_schema VARCHAR(255),
[time] DATETIMEOFFSET(6),
data VARBINARY(MAX),
extensions VARBINARY(MAX),
processed_flag BIT DEFAULT 0,
version TINYINT NOT NULL CHECK (version BETWEEN 0 AND 1),
PRIMARY KEY (id)
);
CREATE TABLE workflow_instance_entity
(
application_id VARCHAR(63) NOT NULL,
instance_id VARCHAR(26) NOT NULL,
workflow_name VARCHAR(255) NOT NULL,
workflow_namespace VARCHAR(255) NOT NULL,
workflow_version VARCHAR(255) NOT NULL,
started_at DATETIMEOFFSET(6) NOT NULL,
status TINYINT CHECK (status BETWEEN 0 AND 6),
input VARBINARY(MAX),
PRIMARY KEY (application_id, instance_id)
);
CREATE TABLE task_info_entity
(
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(26) NOT NULL,
json_pointer VARCHAR(679) NOT NULL,
iteration INT NOT NULL,
task_type INT NOT NULL CHECK (task_type IN (1, 2)),
is_end_node BIT,
retry_attempt INT,
instant DATETIMEOFFSET(6),
next_position VARCHAR(255),
context VARBINARY(MAX),
model VARBINARY(MAX),
context_hash_key VARBINARY(MAX),
context_hash_index VARBINARY(MAX),
model_hash_key VARBINARY(MAX),
model_hash_index VARBINARY(MAX),
PRIMARY KEY (iteration, application_id, json_pointer, workflow_instance_id),
CHECK (task_type <> 1 OR (is_end_node IS NOT NULL)),
CHECK (task_type <> 2 OR (retry_attempt IS NOT NULL)),
CONSTRAINT fk_task_workflow_instance
FOREIGN KEY (application_id, workflow_instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
CREATE TABLE hash_mapping_info_entity
(
id VARCHAR(255) NOT NULL,
instance VARCHAR(255),
[key] VARBINARY(255),
data VARBINARY(MAX),
PRIMARY KEY (id)
);
CREATE INDEX hashKey_idx ON hash_mapping_info_entity ([key]);
CREATE INDEX instance_idx ON hash_mapping_info_entity (instance);
CREATE TABLE task_metadata_entity
(
meta_name VARCHAR(128) NOT NULL,
iteration INT NOT NULL,
json_pointer VARCHAR(679) NOT NULL,
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(26) NOT NULL,
hash_key VARBINARY(MAX),
hash_index VARBINARY(MAX),
raw_value VARBINARY(MAX),
PRIMARY KEY (meta_name, iteration, json_pointer, application_id, workflow_instance_id),
CONSTRAINT fk_task_metadata_task
FOREIGN KEY (iteration, application_id, json_pointer, workflow_instance_id)
REFERENCES task_info_entity (iteration, application_id, json_pointer, workflow_instance_id)
ON DELETE CASCADE
);
CREATE TABLE workflow_metadata_entity
(
meta_name VARCHAR(128) NOT NULL,
instance_id VARCHAR(26) NOT NULL,
application_id VARCHAR(63) NOT NULL,
workflow_instance_id VARCHAR(255),
hash_key VARBINARY(MAX),
hash_index VARBINARY(MAX),
raw_value VARBINARY(MAX),
PRIMARY KEY (meta_name, instance_id, application_id),
CONSTRAINT fk_workflow_metadata_workflow
FOREIGN KEY (application_id, instance_id)
REFERENCES workflow_instance_entity (application_id, instance_id)
ON DELETE CASCADE
);
|
Pick the script that matches your target database and adapt it further if your schema or naming conventions differ.
Note that the |
Versioning convention
Scripts follow V{quarkus-flow version}.{sequence}Description.sql, so a script’s version communicates which Quarkus Flow release introduced it.
quarkus-flow-db-migration and quarkus-flow-db-migration-quartz both start at V1.0.0.
Upgrading an existing database
If you’re already running with quarkus.hibernate-orm.schema-management.strategy=update (or Quartz’s schema was created by hand) and want to switch to managed migrations without recreating your tables, use Flyway’s baseline-on-migrate.
The baseline-version must match that stream’s own first script - Flyway treats every migration at or below the baseline version as already applied and skips it, so a lower value does not skip that first script, it just hides the problem until the baseline path actually engages against a populated database, at which point Flyway tries to run CREATE TABLE a second time and fails on already-existing objects.
For quarkus-flow-db-migration (first script V1.0.0__), prefix these with its flow-runtime named Flyway configuration:
quarkus.flyway.flow-runtime.baseline-on-migrate=true
quarkus.flyway.flow-runtime.baseline-version=1.0.0
For quarkus-flow-db-migration-quartz (first script V1.0.0__), prefix these with its flow-quartz named Flyway configuration:
quarkus.flyway.flow-quartz.baseline-on-migrate=true
quarkus.flyway.flow-quartz.baseline-version=1.0.0
See Quartz workflow scheduler for the full Quartz setup.
Back up your database first, and rehearse the baseline against a copy of it before running it against production, baseline-on-migrate tells Flyway "assume everything up to this version already exists," so any drift between your current schema and the version you baseline against will not be caught.
Upgrading from Quartz’s old default-location Flyway setup
Before quarkus-flow-db-migration-quartz existed, the QRTZ_* script shipped inside quarkus-flow-quartz-scheduler itself, on Flyway’s default classpath location (db/migration), where it was picked up automatically whenever an application set quarkus.flyway.migrate-at-start=true.
That script has moved to this extension’s own db/flow-migration/quartz/postgresql location with no compatibility copy left behind: quarkus-flow-quartz-scheduler no longer ships the script, or a quarkus-flyway dependency, at all.
quarkus.quartz is still a preview-status extension, so there is no stable, generally-adopted setup this needs to keep working without changes - an application still relying on that default-location quarkus.flyway.* configuration gets nothing at the old location and no warning, and must switch explicitly.
To fix it, add quarkus-flow-db-migration-quartz, switch to the flow-quartz datasource and Flyway configuration shown above, and apply the baseline step from Upgrading an existing database - the QRTZ_* tables already exist, so this is that section’s populated-database case, with one addition: the history table name is also changing, from the old setup’s flyway_quarkus_history to this extension’s flyway_flow_quartz_history. Starting from an empty history table under the new name, Flyway has no record that V1.0.0__QuarkusQuartzTasks.sql already ran, so the baseline is required even though an equivalent script already ran once under the old setup (there, as part of `quarkus-flow-quartz-scheduler’s own Flyway setup).
See Migration Guide: 1.2.x to 1.3.0 for the complete step-by-step walkthrough of this upgrade.