codeconsole opened a new pull request, #16208:
URL: https://github.com/apache/grails-core/pull/16208

   Two settings for the MongoDB index build that runs when the datastore 
starts, plus the reporting to make either decision an informed one.
   
   ## `grails.mongodb.buildIndexes`
   
   ```groovy
   grails {
       mongodb {
           buildIndexes = false
       }
   }
   ```
   
   GORM creates and reconciles every index declared in a mapping block each 
time the datastore starts, with no way to switch it off. That is unwanted when 
deploying against live data whose indexes are managed separately, by a DBA or a 
migration step: the deployment builds indexes against production collections 
and reconciles the index set the running application depends on.
   
   With the setting off, no `createIndex` or `collMod` is issued for any domain 
class and the indexes on the server are left exactly as they are. Persistence 
and querying are unaffected and keep using whichever indexes exist. It also 
covers domain classes registered after startup, and resolves per connection 
like every other connection setting, so index building can be switched off 
globally and left on for one connection:
   
   ```groovy
   grails {
       mongodb {
           buildIndexes = false
           connections {
               reporting {
                   url = "mongodb://localhost/reporting"
                   buildIndexes = true
               }
           }
       }
   }
   ```
   
   A collection that has never started up with index building enabled will have 
no declared indexes at all, so this is for environments where the indexes are 
already in place or are applied by other means. It governs only what GORM 
derives from mapping blocks; an explicit `createIndex` in application code is 
unaffected.
   
   ## `grails.mongodb.buildIndexesAsync`
   
   ```groovy
   grails {
       mongodb {
           buildIndexesAsync = true
       }
   }
   ```
   
   MongoDB answers a `createIndex` only once the index has been built, so by 
default startup waits for every declared index in turn. Measured against 
MongoDB 7.0 with 200k documents: 172ms to create one index on the calling 
thread, 1.2ms to re-issue the same declaration. `background: true` has been 
ignored since MongoDB 4.2 and costs the same.
   
   With this enabled the startup build runs on one daemon thread per 
connection, named `gorm-mongo-index-build-<connection>`, and startup continues 
without waiting. Indexes are still built one at a time rather than all at once 
against the server.
   
   Worth planning for:
   
   - A query issued before its index has been built is served without it — 
correctly, but unindexed. A `unique` index likewise constrains nothing until 
the build finishes.
   - Startup no longer waits, so a failed index build can no longer fail 
startup. It is logged at error level and the application runs without that 
index. The default synchronous build still propagates the exception.
   - It applies to the startup build only. A domain class registered afterwards 
is indexed on the thread registering it, which keeps the tenant context that 
path can depend on.
   
   ## Index build reporting
   
   A successful build previously logged nothing at all — only conflicts, TTL 
updates and failures — so there was no way to tell how much of startup went on 
indexes, and with the async build no signal that it had finished. It now logs 
one summary:
   
   ```
   Index build for database [myDb] finished in 412ms: 2 created, 5 already 
present, from 3 domain class(es)
   ```
   
   The created/already-present split is what makes the elapsed time 
interpretable: a restart that changed no mappings reports everything as already 
present and costs milliseconds, so a summary reporting indexes created is the 
one that accounts for a slow start. A build with failures is logged at `WARN` 
and reports how many. Each index also logs its own elapsed time at `DEBUG` 
under `org.grails.datastore.mapping.core`, which is how to find the single slow 
index behind a slow summary.
   
   `createIndexes` reports `numIndexesBefore` / `numIndexesAfter`, but the 
driver's `createIndex` helper discards the response and returns only the index 
name. Rather than hand-roll the command — the `IndexOptions` to 
index-specification mapping is not worth reimplementing — the build lists the 
indexes a collection already has. That listing is lazy, so an entity declaring 
no indexes costs no round trip, and it replaces the listing the conflict path 
used to make for itself. If it cannot be read, the build still runs and the 
summary falls back to reporting how many declarations were applied.
   
   ## Settings were ignored when the application supplies its own `MongoClient`
   
   Found while testing the above. The constructors taking a `MongoClient` (or a 
`MongoClientSettings.Builder`) built the default connection source from a bare 
`MongoConnectionSourceSettings`, so every `grails.mongodb` setting describing 
how the datastore behaves — `stateless`, `transactional`, `engine`, flush mode, 
`decimalType`, and now `buildIndexes` — was silently left at its default. Only 
`databaseName` survived, because it is set explicitly from the mapping context.
   
   That path is not obscure: Spring Boot's MongoDB auto-configuration 
contributes a `MongoClient` bean and `MongoDbGormAutoConfiguration` hands that 
client to GORM whenever one is present, so a Spring Boot application 
configuring GORM through `grails.mongodb` was being ignored. The settings are 
now bound from the configuration on that path too; the connection details in 
them go unused, as the client arrives already connected.
   
   This is a behaviour change for anyone who had been running on defaults 
without knowing it — a `stateless = true` or `transactional = true` that was 
previously discarded now takes effect.
   
   ## Notes
   
   - Documented in `grails-data-mongodb/docs` under Querying Indexing and 
Advanced Configuration, with the 8.0 release notes updated.
   - The mongo core tests now run against logback rather than the no-op SLF4J 
binding, as `grails-data-neo4j/core` already does, so a test can assert on what 
was logged. The root logger is pinned to `WARN` by a `logback-test.xml`, and 
the build output is unchanged.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to