I have a Spring Boot REST API with 2 endpoints, one calls an Async service to start a long-running job, and another is a synchronous API to get the progress of the job. Job status is stored in a table. The APIs work fine when I run on the embedded tomcat, but the async method does not work on WLS, which is my target env. The sync method is working fine. My weblogic.xml file is as below:
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
<wls:context-root>moph-excel-loader</wls:context-root>
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>org.slf4j.*</wls:package-name>
<wls:package-name>org.springframework.*</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
</wls:weblogic-web-app>
I'm not getting any error messages from WLS or the application, it just hangs there. The synchronous API continues to work fine. I'm not clear what the issue is here and would appreciate some guidance from the community.
Thanks,
EDIT 1:
I have my long running tasks run via a ThreadPoolTaskExecutor
configued as a @Bean
:
@Configuration
@EnableAsync
public class AsyncConfig{
@Bean(name = "asyncFileLoadExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("xlconv-th-");
executor.initialize();
return executor;
}
}
And all my long-running @Service
classes have methods annotated as @Async
:
@Service
public class FileLoaderService {
private static final Logger LOGGER = LoggerFactory.getLogger(FileLoaderService.class);
//Autowired services
@Async("asyncFileLoadExecutor")
public CompletableFuture<Void> loadFile(JobDto job, String fileName) throws IOException, OpenXML4JException, SAXException, ParserConfigurationException, ParseException {
//Long running work.
return CompletableFuture.completedFuture(null);
}
}
This one gets called from the RESTController
class and calls other async services in turn to parallelize independent tasks.
EDIT 2: My main class looks like this:
@SpringBootApplication(scanBasePackages = { "nom.side.xls" })
public class ExcelFileLoaderApplication {
public static void main(String[] args) {
SpringApplication.run(ExcelFileLoaderApplication.class, args);
}
}
And this is my only controller class:
@RestController
@RequestMapping("/bulk-loader")
public class BulkLoadController {
private static final Logger LOGGER = LoggerFactory.getLogger(BulkLoadController.class);
@Autowired
private FileLoaderService loaderService;
@Autowired
private JobManagerService jobManagerService;
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public JobDto load(@RequestBody Map<String, String> request) {
JobDto job = jobManagerService.createJob(Paths.get(request.get("fileName")).getFileName().toString());
LOGGER.info("[" + job.getJobId() + "] Parsing file " + request.get("fileName"));
try {
loaderService.loadFile(job, request.get("fileName"));
} catch (IOException | OpenXML4JException | SAXException | ParserConfigurationException
| ParseException e) {
e.printStackTrace();
}
return job;
}
//This one works just fine
@GetMapping(path = "/jobs/{job-id}", produces = MediaType.APPLICATION_JSON_VALUE)
public JobDto progress(@PathVariable(name = "job-id") long jobId) {
return jobManagerService.getJob(jobId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "ERROR: Invalid Job ID " + jobId + "."));
}
}