grails:
profile: web
codegen:
defaultPackage: example.grails
gorm:
reactor:
events: false
dataSource:
dbCreate: create-drop
url: jdbc:h2:mem:application;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driverClassName: org.h2.Driver
username: sa
password: ''
dataSources:
jobrunr:
dbCreate: none
url: jdbc:h2:mem:jobrunr;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driverClassName: org.h2.Driver
username: sa
password: ''
hibernate:
cache:
queries: false
use_second_level_cache: false
use_query_cache: false
jobrunr:
jobs:
default-number-of-retries: 3
server:
port: 8080
environments:
development:
jobrunr:
background-job-server:
enabled: true
worker-count: 2
poll-interval-in-seconds: 5
dashboard:
enabled: true
port: 8000
test:
jobrunr:
background-job-server:
enabled: true
worker-count: 1
poll-interval-in-seconds: 5
dashboard:
enabled: false
production:
jobrunr:
database:
skip-create: true
background-job-server:
enabled: false
dashboard:
enabled: false
miscellaneous:
allow-anonymous-data-usage: false
3 Configure Dedicated Job Storage
JobRunr needs one durable writer data source. Do not point JobRunr at a read replica: workers both read and write job state. The JobRunr storage documentation explains the storage requirements.
The sample separates application persistence from JobRunr persistence. Grails names the default bean dataSource and the named jobrunr source dataSource_jobrunr:
With multiple data sources, relying on type-only auto-configuration can be ambiguous. Instead, the sample supplies an explicit StorageProvider and qualifies the dedicated source. It also installs the JobMapper eagerly:
package example.grails.jobrunr
import javax.sql.DataSource
import org.jobrunr.jobs.mappers.JobMapper
import org.jobrunr.spring.autoconfigure.JobRunrProperties
import org.jobrunr.storage.StorageProvider
import org.jobrunr.storage.StorageProviderUtils.DatabaseOptions
import org.jobrunr.storage.sql.common.SqlStorageProviderFactory
import org.jobrunr.utils.mapper.jackson.JacksonJsonMapper
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class JobRunrStorageConfig {
@Bean
StorageProvider storageProvider(
@Qualifier('dataSource_jobrunr') DataSource jobrunrDataSource,
JobRunrProperties jobRunrProperties
) {
StorageProvider storageProvider = SqlStorageProviderFactory.using(
jobrunrDataSource,
jobRunrProperties.database.tablePrefix,
jobRunrProperties.database.skipCreate ? DatabaseOptions.SKIP_CREATE : DatabaseOptions.CREATE
)
storageProvider.setJobMapper(new JobMapper(new JacksonJsonMapper()))
storageProvider
}
}
The configuration reads jobrunr.database.table-prefix and jobrunr.database.skip-create from JobRunr properties. Set a table prefix when JobRunr must share a schema with other applications or deployments. With skip-create: false, the provider creates its tables, which is useful for this guide’s disposable H2 storage. With skip-create: true, it uses DatabaseOptions.SKIP_CREATE and does not create tables at application startup.
Before any production node starts with skip-create: true, apply the JobRunr schema migrations for the configured database and table prefix. Missing tables must fail startup rather than allowing an application instance to take ownership of production DDL. Production schema management is covered in Production Operations and OSS Boundaries.
Grails must see the configuration class and its components. The application imports the configuration and scans the package containing the listener and handlers:
package example.grails
import example.grails.jobrunr.JobRunrStorageConfig
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.grails.datastore.gorm.boot.autoconfigure.HibernateGormAutoConfiguration
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Import
@Import([HibernateGormAutoConfiguration, JobRunrStorageConfig])
@ComponentScan('example.grails')
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
}