mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
fix(setup): ensure PostgreSQL 18 compatibility (#11484)
# Which Problems Are Solved When starting Zitadel with Postgres version 18, setup fails with the following error: `level=error msg="migration failed" caller=".../cmd/setup/setup.go:373" code=0A000 detail= error="ERROR: partitioned tables cannot be unlogged (SQLSTATE 0A000)" hint= message="partitioned tables cannot be unlogged" name=34_add_cache_schema severity=ERROR` # How the Problems Are Solved - Modify setup step 34 to ensure compatibility with PostgreSQL 18 by changing the creation of the partitioned tables to`LOGGED` tables but keep the partitions `UNLOGGED`. - Added an additional setup step which alters the table persistence of the partitioned tables to `LOGGED`. # Additional Changes - Bumped Postgres compatibility to version 18 in docs. - Ensure default partitions for cache tables ## Additional Context - closes https://github.com/zitadel/zitadel/issues/10712 - backport to v4 - migration from PostgreSQL version 17 to 18 was verified using `pg_dumpall` and restoring the created backup file - and new setups using PostgreSQL version 18 directly --------- Co-authored-by: Copilot <[email protected]>
This commit is contained in:
@@ -24,7 +24,7 @@ services:
|
|||||||
- "4200:4200"
|
- "4200:4200"
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:17
|
image: postgres:18
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env.db
|
- ./.env.db
|
||||||
@@ -40,7 +40,7 @@ services:
|
|||||||
- 5432:5432
|
- 5432:5432
|
||||||
|
|
||||||
db-api-integration:
|
db-api-integration:
|
||||||
image: 'postgres:17'
|
image: 'postgres:18'
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env.db
|
- ./.env.db
|
||||||
environment:
|
environment:
|
||||||
@@ -61,7 +61,7 @@ services:
|
|||||||
- 6379:6379
|
- 6379:6379
|
||||||
|
|
||||||
db-functional-ui:
|
db-functional-ui:
|
||||||
image: 'postgres:17'
|
image: 'postgres:18'
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env.db
|
- ./.env.db
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ PostgreSQL is the default database for ZITADEL due to its reliability, robustnes
|
|||||||
|
|
||||||
If you are using Zitadel v2 and want to use a PostgreSQL database, you can [overwrite the default configuration](/self-hosting/manage/configure/configure).
|
If you are using Zitadel v2 and want to use a PostgreSQL database, you can [overwrite the default configuration](/self-hosting/manage/configure/configure).
|
||||||
|
|
||||||
Currently, versions 14 to 17 are supported.
|
Currently, versions 14 to 18 are supported.
|
||||||
|
|
||||||
Postgres can be configured as follows:
|
Postgres can be configured as follows:
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
create schema if not exists cache;
|
create schema if not exists cache;
|
||||||
|
|
||||||
create unlogged table if not exists cache.objects (
|
create table if not exists cache.objects (
|
||||||
cache_name varchar not null,
|
cache_name varchar not null,
|
||||||
id uuid not null default gen_random_uuid(),
|
id uuid not null default gen_random_uuid(),
|
||||||
created_at timestamptz not null default now(),
|
created_at timestamptz not null default now(),
|
||||||
@@ -11,7 +11,10 @@ create unlogged table if not exists cache.objects (
|
|||||||
)
|
)
|
||||||
partition by list (cache_name);
|
partition by list (cache_name);
|
||||||
|
|
||||||
create unlogged table if not exists cache.string_keys(
|
create unlogged table if not exists cache.objects_default
|
||||||
|
PARTITION OF cache.objects DEFAULT;
|
||||||
|
|
||||||
|
create table if not exists cache.string_keys(
|
||||||
cache_name varchar not null check (cache_name <> ''),
|
cache_name varchar not null check (cache_name <> ''),
|
||||||
index_id integer not null check (index_id > 0),
|
index_id integer not null check (index_id > 0),
|
||||||
index_key varchar not null check (index_key <> ''),
|
index_key varchar not null check (index_key <> ''),
|
||||||
@@ -27,3 +30,6 @@ partition by list (cache_name);
|
|||||||
|
|
||||||
create index if not exists string_keys_object_id_idx
|
create index if not exists string_keys_object_id_idx
|
||||||
on cache.string_keys (cache_name, object_id); -- for delete cascade
|
on cache.string_keys (cache_name, object_id); -- for delete cascade
|
||||||
|
|
||||||
|
create unlogged table if not exists cache.string_keys_default
|
||||||
|
PARTITION OF cache.string_keys DEFAULT;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package setup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed 69.sql
|
||||||
|
cacheTablesLogged string
|
||||||
|
)
|
||||||
|
|
||||||
|
type CacheTablesLogged struct {
|
||||||
|
dbClient *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mig *CacheTablesLogged) Execute(ctx context.Context, _ eventstore.Event) error {
|
||||||
|
_, err := mig.dbClient.ExecContext(ctx, cacheTablesLogged)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mig *CacheTablesLogged) String() string {
|
||||||
|
return "69_cache_tables_logged"
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
DO
|
||||||
|
$do$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_class WHERE oid = 'cache.objects'::REGCLASS AND relpersistence = 'u') THEN
|
||||||
|
ALTER TABLE IF EXISTS cache.objects
|
||||||
|
SET LOGGED;
|
||||||
|
END IF;
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_class WHERE oid = 'cache.string_keys'::REGCLASS AND relpersistence = 'u') THEN
|
||||||
|
ALTER TABLE IF EXISTS cache.string_keys
|
||||||
|
SET LOGGED;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
CREATE UNLOGGED TABLE IF NOT EXISTS cache.objects_default
|
||||||
|
PARTITION OF cache.objects DEFAULT;
|
||||||
|
|
||||||
|
CREATE UNLOGGED TABLE IF NOT EXISTS cache.string_keys_default
|
||||||
|
PARTITION OF cache.string_keys DEFAULT;
|
||||||
|
END
|
||||||
|
$do$
|
||||||
@@ -177,6 +177,7 @@ type Steps struct {
|
|||||||
s66SessionRecoveryCodeCheckedAt *SessionRecoveryCodeCheckedAt
|
s66SessionRecoveryCodeCheckedAt *SessionRecoveryCodeCheckedAt
|
||||||
s67SyncMemberRoleFields *SyncMemberRoleFields
|
s67SyncMemberRoleFields *SyncMemberRoleFields
|
||||||
s68TargetAddPayloadTypeColumn *TargetAddPayloadTypeColumn
|
s68TargetAddPayloadTypeColumn *TargetAddPayloadTypeColumn
|
||||||
|
s69CacheTablesLogged *CacheTablesLogged
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustNewSteps(v *viper.Viper) *Steps {
|
func MustNewSteps(v *viper.Viper) *Steps {
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
|
|||||||
steps.s66SessionRecoveryCodeCheckedAt = &SessionRecoveryCodeCheckedAt{dbClient: dbClient}
|
steps.s66SessionRecoveryCodeCheckedAt = &SessionRecoveryCodeCheckedAt{dbClient: dbClient}
|
||||||
steps.s67SyncMemberRoleFields = &SyncMemberRoleFields{dbClient: dbClient}
|
steps.s67SyncMemberRoleFields = &SyncMemberRoleFields{dbClient: dbClient}
|
||||||
steps.s68TargetAddPayloadTypeColumn = &TargetAddPayloadTypeColumn{dbClient: dbClient}
|
steps.s68TargetAddPayloadTypeColumn = &TargetAddPayloadTypeColumn{dbClient: dbClient}
|
||||||
|
steps.s69CacheTablesLogged = &CacheTablesLogged{dbClient: dbClient}
|
||||||
|
|
||||||
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil, nil)
|
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil, nil)
|
||||||
logging.OnError(err).Fatal("unable to start projections")
|
logging.OnError(err).Fatal("unable to start projections")
|
||||||
@@ -303,6 +304,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
|
|||||||
steps.s64ChangePushPosition,
|
steps.s64ChangePushPosition,
|
||||||
steps.s65FixUserMetadata5Index,
|
steps.s65FixUserMetadata5Index,
|
||||||
steps.s67SyncMemberRoleFields,
|
steps.s67SyncMemberRoleFields,
|
||||||
|
steps.s69CacheTablesLogged,
|
||||||
} {
|
} {
|
||||||
setupErr = executeMigration(ctx, eventstoreClient, step, "migration failed")
|
setupErr = executeMigration(ctx, eventstoreClient, step, "migration failed")
|
||||||
if setupErr != nil {
|
if setupErr != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user