I have a java Spring boot app on Ubuntu that (mainly) runs fine.
But, if I go to a website that calls a Controller - data is fetched, the website is shown, but after a few seconds - the app is killed! (ps -ef doesn't show the app, and the controllers are all dead).
I tried to catch the Spring close operation in this class:
@Slf4j@Componentpublic class AlpacaServiceLifeCycle implements CommandLineRunner { @Override public void run(String... arg0) throws Exception { log.info("###START FROM THE LIFECYCLE###"); } @PreDestroy public void onExit() { log.info("###STOP FROM THE LIFECYCLE###"); new Exception().printStackTrace(); }}
And this class:
@Componentpublic class ContextClosedEventListener { @EventListener(ContextClosedEvent.class) public void onContextClosedEvent(ContextClosedEvent contextClosedEvent) { System.out.println("ContextClosedEvent occurred at millis: " + contextClosedEvent.getTimestamp()); new Exception().printStackTrace(); }}
Also, the problematic class implements SmartLifecycle.
But still, nothing is shown!
If the app runs out of memory, an exception is thrown and file is created that tells me what happened. But not here (you can see that the data is saved in a table - the table size (with one row) is 0.02MB).
Could it be that somehow ubuntu kills the app?
The problematic controller:
@Slf4j@RestController@RequestMapping("/positions")public class PositionsController implements SmartLifecycle { private static final String BODY_HTML_END = "\t</body>\n" +"</html>"; private static final String alpacaLink = "https://app.alpaca.markets/trade/{*}"; @Autowired private PositionsFetchService positionsFetchService; @Autowired private SellStocksDailyIndicatorScheduler sellStocksDailyIndicator; @Autowired private DailyPurchaseLogCache dailyPurchaseLogCache; @Resource private PositionTableRepository positionTableRepository; @RequestMapping(value = "/list", method = RequestMethod.GET, produces = {MediaType.TEXT_HTML_VALUE}) @ResponseStatus(HttpStatus.OK) public String list(@RequestParam(name = "soa", required = false) Boolean showOnlyAvailable) throws Exception { log.info("Positions called"); if (positionTableRepository.findByFetchDate(LocalDate.now()) != null) { log.info("Fetching from DB"); return positionTableRepository.findByFetchDate(LocalDate.now()).getTableStr(); } Set<OutptOrderEntity> allOrders = dailyPurchaseLogCache.fetchAllOrders(false); StringBuilder theTable = new StringBuilder(CONSTANT_VISIBLE_HEADERS +"\t\t<table class=\"sortable\">"); theTable = new StringBuilder(theTable.toString().replace("*TITLE*", "Positions")); theTable.append("\t\t<th>#</th>\n"); theTable.append("\t\t<th>Created At</th>\n"); theTable.append("\t\t<th>symbol</th>\n"); theTable.append("\t\t<th>avg_entry_price</th>\n"); theTable.append("\t\t<th>current_price</th>\n"); theTable.append("\t\t<th>qty_available</th>\n"); theTable.append("\t\t<th>cost_basis</th>\n"); theTable.append("\t\t<th>market_value</th>\n"); theTable.append("\t\t<th>diff</th>\n"); theTable.append("\t\t<th>change_today</th>\n"); theTable.append("\t\t<th>lastday_price</th>\n"); theTable.append("\t\t<th>qty</th>\n"); theTable.append("\t\t<th>unrealized_pl</th>\n"); List<PositionEntity> positionEntities = positionsFetchService.fetch(); for (int i = 0; i < positionEntities.size(); i++) { PositionEntity curr = positionEntities.get(i); if (curr.getAvg_entry_price() != null && curr.getCurrent_price() != null) { try { String symbol = curr.getSymbol(); List<OutptOrderEntity> ordersOfSymbol = allOrders.stream().filter(s -> s.getSymbol().equals(symbol)).collect(Collectors.toList()); if (ordersOfSymbol.isEmpty()) { log.warn("Symbol {} doesn't have data", symbol); continue; } LocalDateTime createdAt = ordersOfSymbol.get(ordersOfSymbol.size() - 1).getCreated_at(); if (showOnlyAvailable && Float.parseFloat(curr.getQty_available()) > 0f) { theTable.append(new TableData(false, alpacaLink.replace("{*}", curr.getSymbol()), i + 1, createdAt, curr.getSymbol(), curr.getAvg_entry_price(), curr.getCurrent_price(), curr.getQty_available(), curr.getCost_basis(), curr.getMarket_value(), Float.parseFloat(curr.getMarket_value()) - Float.parseFloat(curr.getCost_basis()), curr.getChange_today(), curr.getLastday_price(), curr.getQty(), curr.getUnrealized_pl()). createString(Float.parseFloat(curr.getCurrent_price()) > Float.parseFloat(curr.getAvg_entry_price()))); } else if (!showOnlyAvailable) { theTable.append(new TableData(false, alpacaLink.replace("{*}", symbol), i + 1, createdAt, curr.getSymbol(), curr.getAvg_entry_price(), curr.getCurrent_price(), curr.getQty_available(), curr.getCost_basis(), curr.getMarket_value(), Float.parseFloat(curr.getMarket_value()) - Float.parseFloat(curr.getCost_basis()), curr.getChange_today(), curr.getLastday_price(), curr.getQty(), curr.getUnrealized_pl()). createString(Float.parseFloat(curr.getCurrent_price()) > Float.parseFloat(curr.getAvg_entry_price()))); } } catch (Exception e) { log.error(e.toString(), e); } } } theTable.append("\t\t\t<script src=\"https://www.kryogenix.org/code/browser/sorttable/sorttable.js\"></script>"); theTable.append("\n\t\t</table>\n"); theTable.append(BODY_HTML_END); log.info("Fetched all positions"); positionTableRepository.save(new PositionsTableEntity(theTable.toString())); return theTable.toString(); } @RequestMapping(value = "/sell_qty_exists", method = RequestMethod.GET, produces = {MediaType.TEXT_HTML_VALUE}) @ResponseStatus(HttpStatus.OK) public void sellQtyExists() throws Exception { sellStocksDailyIndicator.scalpOnAllIndicators(); } @Override public boolean isAutoStartup() { return false; } @Override public void stop(Runnable runnable) { new Exception().printStackTrace(); } @Override public void start() { } @Override public void stop() { new Exception().printStackTrace(); } @Override public boolean isRunning() { return false; } @Override public int getPhase() { return 0; }}