Calling a Client Via Spring @schedule Cron Job
In this article, a cron job will be set up that will run parametrically in a certain period using Spring's scheduling feature.
Join the DZone community and get the full member experience.
Join For FreeIn this article, a cron job will be set up that will run parametrically in a certain period using Spring's scheduling feature. Period information will be adjustable parametrically from the application.properties file.
Overview
In the example, parameter information is given to run every minute.
schedule.minute.param:1

The schedule method will be run in a minute time period. It will trigger the method we want to call within the service class. This method will call a client jar from integration_microservice via feign client and get the response information.
For this architecture, we will have two microservices on Spring Boot. The first of these will be job_microservice and the second will be integration_microservice.
The schedule method in job_microservice will be run periodically and the service impl will be called.
The jobIntegrationClientFacades service class will be called from the ServiceImpl class. JobIntegrationFeignClient class will be called from jobIntegrationClientFacades to go to integration_microservice.
Access to integration_microservice will be provided through the @FeignClient annotation within the JobIntegrationFeignClient class.
The response received via the relevant client.jar controller class in integration_microservice will be returned to job_microservice.
Various validations can be made on the response received in job_microservice service_impl.
Logging can be done according to the response. Error situations can be separated and logged according to the incoming response code. On successful response, the flow will be terminated. If desired, the successful response can be logged, but it may cause the log size to increase.





The following flow should be followed for two microservices:
1. job_microservice:
- A new Spring Boot Maven module named
job_microserviceshould be created. spring-cloud-starter-openfeignshould be added as a dependency.

2. integration_microservice:
- A new Spring Boot Maven module named
integration_microserviceshould be created. spring-cloud-starter-webshould be added as a dependency.

Note: Creating a client in integration_microservice and using client features and methods are not covered in this article, as they are the subject of another article. Client creation stages are out of scope in this article.
job_microservice
- In order to run the Spring
@schedulefeature in theJobApplication.ktclass, the@EnableSchedulingannotation must be added. - In order to communicate between two microservices via
feignclient, the@EnableFeignClientsannotation must be added.
JobApplication.kt:
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.cloud.openfeign.EnableFeignClients
import org.springframework.scheduling.annotation.EnableScheduling
@SpringBootApplication
@EnableFeignClients
@EnableScheduling
class JobmicroserviceApplication
fun main(args: Array<String>) {
runApplication<JobmicroserviceApplication>(*args)
}
CronScheduler
- A class named
CronScheduleris created with@componentannotation. - With
@Value("\${schedule.minute.param:}"), the "schedule.minute.param" value in the application properties file is read parametrically. - It is run on a minute basis with the "
schedule.minute.param" value taken from the parametric application properties file with@Scheduled(cron = "* */\${schedule.minute.param} * * * ?").- First
*: Seconds of operation - Second
*: Minute-based operation - Third
*: Clockwise operation - Fourth
*: Day of month operation - Fifth
*: Month-based operation - Sixth
*: Day of the week run
- First
The @schedule annotation is added right above the relevant method. As can be seen below, the prepareClientCall function is defined as a unit return type to perform the operation without waiting for any response.
By including jobService, prepareClientCall in the jobService interface is called.
CronScheduler.kt:
@Component
class CronScheduler(val jobService: JobService) {
@Value("\${schedule.minute.param:}")
@Scheduled(cron = "* */\${schedule.minute.param} * * * ?")
fun prepareClientCall(): Unit {
jobService.prepareClientCall()
}
}
JobService.kt
interface JobService {
fun prepareClientCall(): Unit
}
- The
prepareClientCallmethod in theJobServiceImplclass is called by the@schedulefunction. Inside, theprepareClientCall()method injobIntegrationClientFacadesis called. - Client response is set to the response object.
ResponseCodein the response is controlled withResponseControl.- The response object here may vary depending on the client you will call. The
responseCodehere is given as an example. - "
0" appeared as a success inResponsecontroland was returned. In the success case, the flow is terminated. - It is logged as a "
-2" system exception and a "-1" business exception. Theelsepart has been thrown away. - The exception is logged in the main function.
Note: The response object here is given through the sample client.
JobServiceImpl.kt:
@Service
class JobServiceImpl(
private val jobIntegrationClientFacades: JobIntegrationClientFacades,
) : JobService {
private val log = logger()
fun responseControl(response: ResponseEntity<ClientResult>) {
if (result.body?.resultCode ?: -3 == 0) {
log.info("resultCode - " + result.body?.resultCode + System.currentTimeMillis() / 1000 )
return; // success case
} else if (result.body?.resultCode ?: -3 == -2) {
log.info("resultCode - " + result.body?.resultCode + System.currentTimeMillis() / 1000 ) // -2 system exception
} else if (result.body?.resultCode ?: -3 == -1) {
log.info("resultCode - " + result.body?.resultCode + System.currentTimeMillis() / 1000 ) // -1 business exception
} else if (result.body?.resultCode ?: -3 == -3) {
log.info("resultCode - " + result.body?.resultCode + System.currentTimeMillis() / 1000 ) // -3 null pointer exception
} else {
throw e
}
}
override
fun prepareClientCall(): Unit {
try {
val response = jobIntegrationClientFacades.prepareClientCall()
responseControl(response)
} catch (exp: Exception) {
log.info("exception - " + exp + System.currentTimeMillis() / 1000 ) // exception
}
}
}
Facades
- Below,
JobIntegrationClientis called fromJobIntegrationClientFacades. JobIntegrationFeignClientis called fromJobIntegrationClient.- A
postMappingrequest was provided tointegration_microservicewithfeignClientto callclient.jarinJobIntegrationFeignClient.
JobIntegrationClientFacades.kt:
@Service
class JobIntegrationClientFacades(val jobIntegrationClient: JobIntegrationClient) {
fun prepareClientCall(): ResponseEntity<ClientResult> {
return jobIntegrationClient.prepareClientCall()
}
}
JobIntegrationClient.kt:
@Service
class JobIntegrationClient(
val jobIntegrationFeignClient: JobIntegrationFeignClient
) {
fun prepareClientCall(): ResponseEntity<ClientResult> {
return jobIntegrationFeignClient.prepareClientCall()
}
}
JobIntegrationFeignClient.kt:
@FeignClient("integration_microservice", url = "http://localhost:10000")
interface JobIntegrationFeignClient {
@PostMapping("/jobIntegrationClient/prepareClientCall")
fun prepareClientCall(): ResponseEntity<ClientResult>
}
integration_microservice
Controller
- The
@RequestMapping("/jobIntegrationClient")request that comes with theRestControllerannotation is checked. - The correctness of matching
"/prepareClientCall"with@PostMapping("/prepareClientCall")is checked. prepareClientCall()injobIntegrationClientServiceis called.- The
prepareClientCall()function in theJobIntegrationClientServiceImplis called from theJobIntegrationClientServiceinterface. - The
prepareClientCall()function is called from the client that you want to call fromJobIntegrationClientServiceImpl.
JobController.kt:
@RestController
@RequestMapping("/jobIntegrationClient")
class JobController(
val jobIntegrationClientService: jobIntegrationClientService
) {
@PostMapping("/prepareClientCall")
fun prepareClientCall(): ResponseEntity<ClientResult> {
return jobIntegrationClientService.prepareClientCall()
}
}
JobIntegrationClientService.kt:
interface JobIntegrationClientService {
fun prepareClientCall(): ResponseEntity<ClientResult>
}
JobIntegrationClientServiceImpl.kt:
@Service
class JobIntegrationClientServiceImpl(
private val xClient: XClient
) : JobIntegrationClientService {
override
fun prepareClientCall(): ResponseEntity<ClientResult> {
return xClient.prepareClientCall()
}
}
- The
Responseobject is returned to theJobIntegrationFeignClient prepareClientCall()function injob_microservicevia theJobControllerasResponseEntity<ClientResult>. - A response is received in
JobServiceImplinjob_microservice.
JobIntegrationFeignClient.kt:
@FeignClient("integration_microservice", url = "http://localhost:10000")
interface JobIntegrationFeignClient {
@PostMapping("/jobIntegrationClient/prepareClientCall")
fun prepareClientCall(): ResponseEntity<ClientResult>
}
Opinions expressed by DZone contributors are their own.
Comments