Skip to content

Spring Boot ​

simba-spring-boot-starter builds one Simba client over the backend on the classpath, runs @SimbaScheduled and @SimbaPartitioned methods, and adds Micrometer metrics, the simba Actuator endpoint and the simba health indicator.

Properties ​

PropertyDefaultDescription
simba.enabledtrueEnables the whole auto-configuration
simba.backend—jdbc, redis or zookeeper; required when several backend modules are active
simba.session.lease-duration15sThe backend expires the session this long after its last keep-alive
simba.session.renew-intervallease-duration / 3Keep-alive period; at most half of the lease duration
simba.session.drift0.01Upper bound of the clock rate difference between a node and the backend, in [0, 0.5)
simba.session.margin50msExtra safety subtracted from every local deadline
simba.jdbc.enabledtrueEnables the JDBC backend
simba.jdbc.dialectdetectedmysql or postgresql; detected from the DataSource when unset
simba.jdbc.query-timeoutrenew intervalPer-statement timeout
simba.redis.enabledtrueEnables the Redis backend
simba.redis.wait-replicas0When positive, a new term counts only once that many replicas acknowledged it (WAIT); not on a Cluster
simba.redis.wait-timeout1sHow long WAIT waits
simba.redis.route-by-slottrue on a ClusterSplit script calls by hash slot
simba.zookeeper.enabledtrueEnables the Zookeeper backend
simba.zookeeper.connect-stringlocalhost:2181Ensemble the backend opens its sessions on
simba.zookeeper.root/simbaParent path of the lease and group nodes
simba.zookeeper.connection-timeout15sHow long opening a session may take
simba.zookeeper.auth.schemedigestAuthentication scheme every Zookeeper client adds
simba.zookeeper.auth.credentials—Auth data of the scheme (UTF-8), e.g. user:password for digest; unset: no authentication
simba.zookeeper.aclautoACL of the nodes the backend creates: open (OPEN_ACL_UNSAFE), creator (CREATOR_ALL_ACL, needs credentials) or auto (creator with credentials, else open); an ACLProvider bean takes precedence
simba.scheduling.enabledtrueRuns @SimbaScheduled and @SimbaPartitioned methods
simba.metrics.enabledtrueRecords Micrometer metrics when a MeterRegistry bean exists
management.health.simba.enabledtrueThe simba health indicator

The session properties are explained in Concepts and Correctness; invalid combinations fail startup. A typical configuration:

yaml
simba:
  backend: redis            # only needed with several backend modules on the classpath
  session:
    lease-duration: 15s
management:
  endpoints:
    web:
      exposure:
        include: health,simba

Beans the Starter Creates ​

BeanCondition
LeaseBackend (JdbcLeaseBackend, RedisLeaseBackend or ZookeeperLeaseBackend)The backend is active and the application defines no LeaseBackend; JDBC needs a single DataSource, Redis a single RedisConnectionFactory; Zookeeper uses an ACLProvider and a ZKClientConfig bean when present
SimbaA LeaseBackend bean exists; built with simba.session.* and every SimbaEventListener bean
SimbaLifecycleCloses the client on shutdown
SimbaScheduledBeanPostProcessorsimba.scheduling.enabled
MicrometerSimbaEventListenerMicrometer on the classpath, a MeterRegistry bean, simba.metrics.enabled
SimbaEndpoint (simba)Actuator on the classpath and the endpoint available (enabled and exposed)
SimbaHealthIndicator (simba)Actuator on the classpath and management.health.simba.enabled

Every bean except the infrastructure (SimbaBackendSelection, the startup check of simba.backend, and SimbaScheduledBeanPostProcessor) is @ConditionalOnMissingBean: define your own to replace it. To customize the client beyond the properties (executors, a fixed seed), define the Simba bean yourself with Simba.builder().

Annotated Methods ​

@SimbaScheduled runs a bean method on the leader of an election; @SimbaPartitioned runs it for every partition of a group this node leads. Both start after the context refreshed and stop on shutdown. Their attributes and method signatures are on the Leader Work page. The lease names they elect (the name of @SimbaScheduled, {group}.{partition} of @SimbaPartitioned) and the groups must be unique across both annotations: startup fails on a conflict.

Shutdown Order ​

  1. SimbaScheduledBeanPostProcessor (phase DEFAULT_PHASE) stops every annotated method: work is interrupted, and each lease is released once its work exited (see Handover Order).
  2. SimbaLifecycle (phase DEFAULT_PHASE - 4096) then closes the Simba client, which revokes every remaining term, closes the session and frees its leases, before lower-phase infrastructure such as connection factories stops.

Elections and locks you started yourself should be stopped before that, e.g. in a ContextClosedEvent listener; closing the client stops them anyway.

Without Spring ​

Build the client with Simba.builder():

kotlin
val simba = Simba.builder()
    .backend(JdbcLeaseBackend.mysql(dataSource, queryTimeout = Duration.ofSeconds(5)))
    .config(SimbaConfig.builder().leaseDuration(Duration.ofSeconds(15)).renewInterval(Duration.ofSeconds(5)).build())
    .listener(myEventListener)
    .build()
Builder methodDefaultDescription
backend(LeaseBackend)requiredThe backend; the client does not close it
config(SimbaConfig)SimbaConfig.builder().build()Session timing, see Timing
listener(SimbaEventListener)noneReceives every SimbaEvent; may be called several times
ioExecutor(Executor)a virtual thread per callRuns backend calls
callbackExecutor(Executor)virtual threadsRuns leadership callbacks, serially per election
workExecutor(Executor)a virtual thread per termRuns leader work
ticker(Ticker)System.nanoTime()Monotonic clock; must advance at the rate of System.nanoTime()
seed(Long)randomSeed of the retry jitter

Create one client per process. Several clients in one process are several sessions: useful only to isolate groups of leases from each other's renewal failures, at the cost of one keep-alive each. close() (or closeAsync()) revokes every term, closes the session and completes after the last callback ran; close the backend afterwards.

Released under the Apache License 2.0.