Add flyway-database-postgresql for grails-forge-analytics-postgres native deploy#15648
Conversation
After PR apache#15647 unblocked dockerBuildNative for grails-forge- analytics-postgres, the resulting native binary built and pushed successfully but the Cloud Run revision failed its startup probe (`The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable within the allocated timeout`). Reproducing locally with a postgres:15.3 sidecar showed the binary crashing during datasource initialization: ERROR io.micronaut.runtime.Micronaut - Error starting Micronaut server: Bean definition [javax.sql.DataSource] could not be loaded: Unsupported Database: PostgreSQL 15.3 Caused by: org.flywaydb.core.api.FlywayException: Unsupported Database: PostgreSQL 15.3 at org.flywaydb.core.internal.database.DatabaseTypeRegister .getDatabaseTypeForConnection(DatabaseTypeRegister.java:131) Flyway 10.x split the per-database DatabaseType implementations out of flyway-core into dedicated modules. After the May-2026 adoption of micronaut-platform pinned us to flyway-core 10.22.0, the analytics service no longer had a PostgreSQL DatabaseType on the runtime classpath, so Flyway's `ServiceLoader<org.flywaydb.core.internal.database.DatabaseType>` returned an empty match for the postgres connection and aborted the schema migration. micronaut-flyway-bom:7.9.2 already manages the matching `org.flywaydb:flyway-database-postgresql:10.22.0` artifact, so adding it as `runtimeOnly` is sufficient. Verified locally with a postgres:15.3 sidecar: HikariPool-1 - Start completed. Flyway - Database: jdbc:postgresql://...:5432/postgres (PostgreSQL 15.3) Flyway - Creating Schema History table "public"."flyway_schema_history" Flyway - Schema "public" is up to date. No migration necessary. io.micronaut.runtime.Micronaut - Startup completed in 193ms. Server Running: http://...:8080 Native binary now binds to PORT=8080 and serves HTTP within the Cloud Run startup probe window. Assisted-by: claude-code:claude-4.7-opus
There was a problem hiding this comment.
Pull request overview
This pull request fixes native startup failures of the grails-forge-analytics-postgres Cloud Run deployment by ensuring Flyway can recognize PostgreSQL at runtime when using Flyway 10.x (where database support is split into per-database modules).
Changes:
- Add the PostgreSQL Flyway database module (
org.flywaydb:flyway-database-postgresql) to the runtime classpath. - Rely on BOM-managed versions for the PostgreSQL JDBC driver and Logback runtime dependency (removing explicit version usage in this module).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| implementation 'io.micronaut.flyway:micronaut-flyway' | ||
| implementation 'io.micronaut.sql:micronaut-jdbc-hikari' | ||
| implementation "org.postgresql:postgresql:$postgresqlVersion" | ||
| implementation "org.postgresql:postgresql" |
| runtimeOnly 'org.flywaydb:flyway-database-postgresql' | ||
| runtimeOnly "ch.qos.logback:logback-classic" | ||
| runtimeOnly 'io.micronaut:micronaut-jackson-databind' |
🚨 TestLens detected 2 failed tests 🚨Here is what you can do:
Test Summary
🏷️ Commit: ca11e8f Test FailuresGroovyChangeLogSpec > outputs a warning message by calling the warn method (:grails-data-hibernate5-dbmigration:test in CI - Groovy Joint Validation Build / build_grails)GroovyChangeLogSpec > updates a database with Groovy Change (:grails-data-hibernate5-dbmigration:test in CI - Groovy Joint Validation Build / build_grails)Muted TestsNote Checks are currently running using the configuration below. Select tests to mute in this pull request: 🔲 GroovyChangeLogSpec > outputs a warning message by calling the warn method Reuse successful test results: 🔲 ♻️ Only rerun the tests that failed or were muted before Click the checkbox to trigger a rerun: 🔲 Rerun jobs Learn more about TestLens at testlens.app. |
…ntime After PR #15647 + #15648 fixed dockerBuildNative + Cloud Run startup for the analytics service, both Forge deploy workflows finally finished green and pushed `next.grails.org` (8.0.0-M1 hotfix branch) and `prev-snapshot.grails.org` (8.0.x) revisions live. start.grails.org still does not list 8.0.0-M1 / 8.0-SNAPSHOT in the Grails Version selector, though, because both backends return: $ curl -i -H 'Origin: https://start.grails.org' https://next.grails.org/versions HTTP/1.1 500 Internal Server Error Content-Type: application/json ... {"_embedded":{"errors":[{"message":"Internal Server Error: Error encoding object [org.grails.forge.api.VersionDTO@..] to JSON: No serializable introspection present for type VersionDTO. Consider adding Serdeable.Serializable annotate to type VersionDTO."}]}, "message":"Internal Server Error"} Reproduced locally (`docker run grails-forge-local:web-netty` against the GraalVM Community 21.0.2-ol9 native image with CORS_ALLOWED_ORIGIN set, then `curl -H 'Origin: https://start.grails.org' /versions`) - identical 500. Root cause: PR #15365 review feedback (commit e1f3013, "Address PR review feedback: telemetry override, forge BOM adoption, publish plugin bump") swapped grails-forge-web-netty's runtime JSON dependency: - runtimeOnly 'io.micronaut:micronaut-jackson-databind' + runtimeOnly 'io.micronaut.serde:micronaut-serde-jackson' with the rationale that "the forge stack is a Micronaut 4 serde- jackson application; the legacy jackson-databind runtime was a copy-paste from an earlier generator template". That is not yet true: every DTO returned by the Forge controllers (VersionDTO, ApplicationTypeDTO, FeatureDTO, FeatureList, SelectOptionsDTO, GormImplDTO, JdkVersionDTO, LanguageDTO, ServletImplDTO, DevelopmentReloadingDTO, GitHubCreateDTO, PreviewDTO, ApplicationTypeList, LinkDTO, the abstract Linkable parent, ...) carries `@Introspected` only - none of them are `@Serdeable` or registered via `@SerdeImport`. Micronaut Serde correctly rejects @Introspected-only classes at runtime, while Micronaut Jackson Databind serialises them via Jackson + bean introspection. The mismatch turns every JSON endpoint behind next.grails.org and prev-snapshot.grails.org into a 500, which is why Forge UI's `versions` fetch is empty for those backends and 8.0.0-M1 is missing from the start.grails.org Grails Version selector. The other Forge modules (forge-api tests, forge-core, analytics- postgres) all still use micronaut-jackson-databind; web-netty was the only inconsistency. Restore web-netty to micronaut-jackson-databind so the runtime matches the rest of the forge stack and the existing @introspected DTOs serialise. A proper end-to-end Serde migration belongs in a separate PR that also annotates every Forge DTO with @Serdeable / @SerdeImport. Verified locally on Docker 29.3.0 with the same Java 21 GraalVM Community 21.0.2-ol9 native-image container the deploy workflows use: $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/versions HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org Vary: Origin Access-Control-Allow-Credentials: true content-type: application/json ... {"_links":{"self":{"href":"http://.../versions","templated":false}}, "versions":{...,"grails.version":"8.0.0-M1",...}} $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/select-options HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org ... Endpoints serve JSON cleanly; CORS allow-origin header is present; the start.grails.org Grails Version selector will pick up 8.0.0-M1 once next.grails.org is redeployed from this commit. Assisted-by: claude-code:claude-4.7-opus
…ntime After PR #15647 + #15648 fixed dockerBuildNative + Cloud Run startup for the analytics service, both Forge deploy workflows finally finished green and pushed `next.grails.org` (8.0.0-M1 hotfix branch) and `prev-snapshot.grails.org` (8.0.x) revisions live. start.grails.org still does not list 8.0.0-M1 / 8.0-SNAPSHOT in the Grails Version selector, though, because both backends return: $ curl -i -H 'Origin: https://start.grails.org' https://next.grails.org/versions HTTP/1.1 500 Internal Server Error Content-Type: application/json ... {"_embedded":{"errors":[{"message":"Internal Server Error: Error encoding object [org.grails.forge.api.VersionDTO@..] to JSON: No serializable introspection present for type VersionDTO. Consider adding Serdeable.Serializable annotate to type VersionDTO."}]}, "message":"Internal Server Error"} Reproduced locally (`docker run grails-forge-local:web-netty` against the GraalVM Community 21.0.2-ol9 native image with CORS_ALLOWED_ORIGIN set, then `curl -H 'Origin: https://start.grails.org' /versions`) - identical 500. Root cause: PR #15365 review feedback (commit e1f3013, "Address PR review feedback: telemetry override, forge BOM adoption, publish plugin bump") swapped grails-forge-web-netty's runtime JSON dependency: - runtimeOnly 'io.micronaut:micronaut-jackson-databind' + runtimeOnly 'io.micronaut.serde:micronaut-serde-jackson' with the rationale that "the forge stack is a Micronaut 4 serde- jackson application; the legacy jackson-databind runtime was a copy-paste from an earlier generator template". That is not yet true: every DTO returned by the Forge controllers (VersionDTO, ApplicationTypeDTO, FeatureDTO, FeatureList, SelectOptionsDTO, GormImplDTO, JdkVersionDTO, LanguageDTO, ServletImplDTO, DevelopmentReloadingDTO, GitHubCreateDTO, PreviewDTO, ApplicationTypeList, LinkDTO, the abstract Linkable parent, ...) carries `@Introspected` only - none of them are `@Serdeable` or registered via `@SerdeImport`. Micronaut Serde correctly rejects @Introspected-only classes at runtime, while Micronaut Jackson Databind serialises them via Jackson + bean introspection. The mismatch turns every JSON endpoint behind next.grails.org and prev-snapshot.grails.org into a 500, which is why Forge UI's `versions` fetch is empty for those backends and 8.0.0-M1 is missing from the start.grails.org Grails Version selector. The other Forge modules (forge-api tests, forge-core, analytics- postgres) all still use micronaut-jackson-databind; web-netty was the only inconsistency. Restore web-netty to micronaut-jackson-databind so the runtime matches the rest of the forge stack and the existing @introspected DTOs serialise. A proper end-to-end Serde migration belongs in a separate PR that also annotates every Forge DTO with @Serdeable / @SerdeImport. Verified locally on Docker 29.3.0 with the same Java 21 GraalVM Community 21.0.2-ol9 native-image container the deploy workflows use: $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/versions HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org Vary: Origin Access-Control-Allow-Credentials: true content-type: application/json ... {"_links":{"self":{"href":"http://.../versions","templated":false}}, "versions":{...,"grails.version":"8.0.0-M1",...}} $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/select-options HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org ... Endpoints serve JSON cleanly; CORS allow-origin header is present; the start.grails.org Grails Version selector will pick up 8.0.0-M1 once next.grails.org is redeployed from this commit. Assisted-by: claude-code:claude-4.7-opus
Summary
After PR #15647 unblocked
dockerBuildNativeforgrails-forge-analytics-postgresand the resulting native binary built and pushed cleanly, the Cloud Run revision still failed its startup probe (run 25578314349 / run 25578315293):That makes 8.0.x's
Deploy to Google Cloud Run(the web-netty one) green again, butDeploy analytics to Google Cloud Runred - this is the third-and-final blocker on the broken Forge deploy pipeline.Root cause
Reproducing the analytics native binary locally on Docker against a
postgres:15.3sidecar showed it crashing during datasource initialization, well before binding to:8080:Flyway 10.x split the per-database
DatabaseTypeSPI implementations out offlyway-coreinto dedicated modules. After the May-2026 adoption ofmicronaut-platform(commitb406076e87) pinned us toflyway-core:10.22.0, the analytics service no longer had a PostgreSQLDatabaseTypeon the runtime classpath, so Flyway'sServiceLoader<org.flywaydb.core.internal.database.DatabaseType>returned an empty match for the postgres connection, threwUnsupported Database, and the Micronaut bootstrap aborted before the HTTP server could bind.Previously this was masked by the earlier
dockerBuildNativefailures - the build never produced an image to deploy, so we never saw the runtime error.Fix
Add
runtimeOnly 'org.flywaydb:flyway-database-postgresql'tograils-forge-analytics-postgres/build.gradle.micronaut-flyway-bom:7.9.2already manages the matchingorg.flywaydb:flyway-database-postgresql:10.22.0artifact, so no explicit version pin is needed:Verification
Local repro on Docker 29.3.0 (post-fix image rebuilt with the same
21.0.2-ol9GraalVM Community native-image container the deploy workflows use):Native binary now binds to
:8080within the Cloud Run startup-probe window. The Cloud Run-side service config (Cloud SQL connection name, secrets, env vars) is unchanged from prior successful deploys (most recent: 2026-04-16 run 24524756128).