Skip to content

Instantly share code, notes, and snippets.

@mgurov
Last active January 12, 2023 14:18
Show Gist options
  • Save mgurov/bb2d10d59ee92b3c684e25297ae49047 to your computer and use it in GitHub Desktop.
Save mgurov/bb2d10d59ee92b3c684e25297ae49047 to your computer and use it in GitHub Desktop.
tracking the cost of the application start/stop in
private val maxInstancesAllowed = System.getProperty("payment-testing.spring.max-instances-allowed", "-1").toInt()
private val instancesRegistered = AtomicInteger(0)
// + class name in src/test/resources/META-INF/spring.factories
// e.g. org.springframework.boot.SpringApplicationRunListener=x.x.x.SpringApplicationTracker
class SpringApplicationTracker(
val application: SpringApplication,
val args: Array<String>,
) : SpringApplicationRunListener {
val logger = LoggerFactory.getLogger("Test spring app #${instancesRegistered.incrementAndGet()}")
val instantiated = Instant.now()
override fun starting(bootstrapContext: ConfigurableBootstrapContext?) {
logger.info("starting: ${bootstrapContext.toString()}")
}
override fun environmentPrepared(bootstrapContext: ConfigurableBootstrapContext?, environment: ConfigurableEnvironment?) {
logger.info("env prepared: ${bootstrapContext.toString()} env: ${environment}")
}
override fun contextPrepared(context: ConfigurableApplicationContext?) {
logger.info("context prepared: ${context.toString()}")
}
override fun contextLoaded(context: ConfigurableApplicationContext?) {
logger.info("context loaded: ${context.toString()}")
}
override fun started(context: ConfigurableApplicationContext) {
val startedAt = context.startupDate
val now = Instant.now().toEpochMilli()
val duration = Duration.ofMillis(now - startedAt)
logger.info("context started in $duration (${duration.seconds} secs) (v ${Duration.ofMillis(now - instantiated.toEpochMilli())}) : ${context}")
}
override fun running(context: ConfigurableApplicationContext?) {
logger.info("context running: ${context.toString()}")
}
override fun failed(context: ConfigurableApplicationContext?, exception: Throwable?) {
logger.info("context failed: ${context.toString()}")
}
}
@Component
class SpringContextTracker {
val logger = LoggerFactory.getLogger("Test spring context #${instancesRegistered.get()}")
init {
logger.info("Test spring context registering #${instancesRegistered.get()}")
if (maxInstancesAllowed >=0 && instancesRegistered.get() > maxInstancesAllowed) {
val message = "The limit of $maxInstancesAllowed has been reached - bailing out. We try to minimize the number of distinct generic Spring contexts started by our tests as per BC-1872. Unsure what to do? Ask Mykola or the rest of the team."
logger.error(message)
throw RuntimeException(message)
}
}
@EventListener
fun handleContextStartedEvent(evt: ContextStartedEvent) {
logger.info("started: ${evt.source} @ ${evt.timestamp}")
}
@EventListener
fun handleContextClosedEvent(evt: ContextClosedEvent) {
logger.info("closed: ${evt.source} @ ${evt.timestamp}")
}
@EventListener
fun handleContextRefreshedEvent(evt: ContextRefreshedEvent) {
logger.info("refreshed: ${evt.source} @ ${evt.timestamp}")
}
@EventListener
fun handleContextStoppedEvent(evt: ContextStoppedEvent) {
logger.info("stopped: ${evt.source} @ ${evt.timestamp}")
}
@EventListener
fun handleApplicationReady(evt: ApplicationReadyEvent) {
logger.info("app ready: ${evt.source} @ ${evt.timestamp}")
}
@EventListener
fun handleApplicationReady(evt: ApplicationStartedEvent) {
logger.info("app started: ${evt.source} @ ${evt.timestamp}")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment