.gitignore | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
README.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/gs/xky/config/AsyncConfig.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/gs/xky/service/DeliveryNoticeService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/gs/xky/service/Impl/DeliveryNoticeServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/gs/xky/service/PurchaseService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/gs/xky/service/XkyService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/gs/xky/task/PurchaseOrderSyncTask.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/gs/xky/task/ScheduledTasks.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/test/java/com/gs/xky/XkyApplicationTests.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
start.bat | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
start.sh | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
.gitignore
@@ -4,6 +4,8 @@ !**/src/main/**/target/ !**/src/test/**/target/ logs ### STS ### .apt_generated .classpath README.md
@@ -155,3 +155,179 @@ 1. ä¿®æ¹å®ä½ç±»æä»¶ä¸çåæ®µå®ä¹ 2. ä¿®æ¹å¯¹åºçSQLæä»¶ä¸çè¡¨ç»æå®ä¹ 3. æ§è¡SQLè¯å¥æ´æ°æ°æ®åºè¡¨ç»æ ## æ§è½ä¼å ç³»ç»å¨å¤çå¤§éæ°æ®æ¶å¯è½ä¼éå°å åå ç¨è¿é«çé®é¢ï¼ç¹å«æ¯å¨æ§è¡ä»¥ä¸æä½æ¶ï¼ 1. éè´è®¢åæ°æ®åæ¥(`syncPurchaseOrderDetails`æ¹æ³) 2. éè´§åæ°æ®å¤ç ### 已宿½çä¼åæªæ½ 1. **åæ¹å¤çæ°æ®**ï¼å°å¤§éæ°æ®åæå°æ¹æ¬¡è¿è¡å¤çï¼åå°ä¸æ¬¡æ§å åå ç¨ 2. **åæ¶éæ¾å¯¹è±¡å¼ç¨**ï¼å¤ç宿¯åå°ä¸å使ç¨ç对象å¼ç¨è®¾ä¸ºnullï¼å¸®å©GCåæ¶å å 3. **ä¼åSQLæ¥è¯¢**ï¼é¿å 䏿¬¡æ§å è½½å¤§éæ°æ®å°å å ### JVMè°ä¼å»ºè®® å¨å¯å¨åºç¨æ¶ï¼å¯ä»¥éè¿ä»¥ä¸JVMåæ°ä¼åå å使ç¨ï¼ ```bash java -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar XkyCollection.jar ``` åæ°è¯´æï¼ - `-Xms512m`ï¼åå§å å å大å°ä¸º512MB - `-Xmx1024m`ï¼æå¤§å å å大å°ä¸º1024MBï¼æ ¹æ®æå¡å¨å®é å¯ç¨å åè°æ´ï¼ - `-XX:MetaspaceSize=128m`ï¼åå§å 空é´å¤§å°ä¸º128MB - `-XX:MaxMetaspaceSize=256m`ï¼æå¤§å 空é´å¤§å°ä¸º256MB - `-XX:+UseG1GC`ï¼ä½¿ç¨G1å徿¶éå¨ï¼éå大å ååºç¨ - `-XX:MaxGCPauseMillis=200`ï¼æå¤§GCæåæ¶é´ç®æ 为200æ¯«ç§ ### çæ§å»ºè®® 1. 使ç¨JConsoleæVisualVMçå·¥å ·çæ§åºç¨å åä½¿ç¨æ åµ 2. å ³æ³¨GCæ¥å¿ï¼åæå åä½¿ç¨æ¨¡å¼ 3. å¨ç产ç¯å¢ä¸ï¼å¯ä»¥æ·»å 以ä¸åæ°å¼å¯GCæ¥å¿ï¼ ``` -Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps ``` ## 常è§é®é¢ææ¥ ### å åæº¢åºï¼OutOfMemoryErrorï¼ å¦æéå°å åæº¢åºé®é¢ï¼ 1. æ£æ¥æ¯å¦æå¤§éæ°æ®ä¸æ¬¡æ§å è½½å°å å 2. 确认æ¯å¦æå åæ³æ¼ï¼å¯¹è±¡åå»ºåæªè¢«éæ¾ï¼ 3. å¢å JVMå å åå¤§å° 4. èè使ç¨å页æ¥è¯¢ææµå¼å¤çå¤§æ°æ®é ### æå¡å¡é¡¿ 妿æå¡åºç°å¡é¡¿ï¼ 1. æ£æ¥æ¯å¦æé¿æ¶é´è¿è¡çäºå¡ 2. ç¡®è®¤æ°æ®åºè¿æ¥æ¯å¦æ£å¸¸éæ¾ 3. æ¥çGCæ¥å¿ï¼ç¡®è®¤æ¯å¦é¢ç¹åçFull GC 4. ä¼åæ°æ®åºæ¥è¯¢ï¼æ·»å éå½çç´¢å¼ ## æä½³å®è·µ 1. é¿å å¨é«å³°ææ§è¡å¤§éæ°æ®åæ¥æä½ 2. 对äºå®æ¶ä»»å¡ï¼éæ©å¨ç³»ç»è´è½½è¾ä½çæ¶æ®µæ§è¡ 3. 使ç¨éå½çæ¹å¤ç大å°ï¼å»ºè®®100-500æ¡è®°å½ï¼ 4. å®ææ¸ çä¸åéè¦çå岿°æ® ## 弿¥ä»»å¡å¤ç ç³»ç»ä½¿ç¨å¼æ¥ä»»å¡å¤çæºå¶æ¥æ§è¡èæ¶æä½ï¼é¿å é»å¡ä¸»çº¿ç¨å宿¶ä»»å¡è°åº¦çº¿ç¨ã主è¦å æ¬ä»¥ä¸å 个é¨åï¼ ### çº¿ç¨æ± é ç½® ç³»ç»é ç½®äºä¸¤ä¸ªä¸ç¨çº¿ç¨æ± ï¼ 1. **éè´è®¢ååæ¥çº¿ç¨æ± (purchaseTaskExecutor)** - æ ¸å¿çº¿ç¨æ°ï¼1ï¼ç¡®ä¿å䏿¶é´åªæä¸ä¸ªéè´åæ¥ä»»å¡å¨æ§è¡ï¼ - æå¤§çº¿ç¨æ°ï¼2 - éå容éï¼5 - æç»çç¥ï¼CallerRunsPolicyï¼è°ç¨è çº¿ç¨æ§è¡ï¼ 2. **éç¨å¼æ¥ä»»å¡çº¿ç¨æ± (taskExecutor)** - æ ¸å¿çº¿ç¨æ°ï¼5 - æå¤§çº¿ç¨æ°ï¼10 - éå容éï¼25 - æç»çç¥ï¼CallerRunsPolicyï¼è°ç¨è çº¿ç¨æ§è¡ï¼ ### 宿¶ä»»å¡ä¼å ææå®æ¶ä»»å¡é½ä½¿ç¨å¼æ¥æ§è¡æ¹å¼ï¼é²æ¢äºç¸é»å¡ï¼ 1. **éè´è®¢å忥任å¡**ï¼æ¯å¤©12:05æ§è¡ä¸æ¬¡ï¼ä½¿ç¨ä¸ç¨çº¿ç¨æ± 2. **设å¤å®æ¶æ°æ®è·å**ï¼æ¯5åéæ§è¡ä¸æ¬¡ï¼ä½¿ç¨éç¨çº¿ç¨æ± 3. **è¡¥å¿é»è¾**ï¼æ¯5åéæ§è¡å¤æ¬¡ï¼ä½¿ç¨éç¨çº¿ç¨æ± 4. **ééæ°æ®åæ¥**ï¼æ¯53åéæ§è¡ä¸æ¬¡ï¼ä½¿ç¨éç¨çº¿ç¨æ± ### 任塿§è¡ç¶æç®¡ç ä½¿ç¨ AtomicBoolean æ è®°ä»»å¡æ§è¡ç¶æï¼é¿å åä¸ä»»å¡é夿§è¡ï¼ ```java private final AtomicBoolean isRunning = new AtomicBoolean(false); // ä»»å¡å¼å§åæ£æ¥ if(!isRunning. compareAndSet(false,true)){ log. info("ä¸ä¸æ¬¡ä»»å¡è¿å¨æ§è¡ä¸ï¼è·³è¿æ¬æ¬¡æ§è¡"); return; } // ä»»å¡ç»æåéç½®ç¶æ finally{ isRunning. set(false); } ``` ### 弿¥ä»»å¡æ§è¡æµç¨ 1. 宿¶å¨è§¦åä»»å¡ 2. æ£æ¥ä»»å¡æ¯å¦å·²å¨è¿è¡ï¼å¦å·²è¿è¡åè·³è¿ 3. å°ä»»å¡æäº¤å°ç¸åºççº¿ç¨æ± 弿¥æ§è¡ 4. 宿¶å¨ç«å³è¿åï¼ä¸çå¾ ä»»å¡å®æ 5. ä»»å¡å¨çº¿ç¨æ± 䏿§è¡å®æ¯åéç½®ç¶ææ è®° è¿ç§æºå¶ç¡®ä¿äºå³ä½¿æä¸ªä»»å¡æ§è¡æ¶é´è¾é¿ï¼ä¹ä¸ä¼å½±åå ¶ä»å®æ¶ä»»å¡çæ£å¸¸æ§è¡ã ## ææ°ä¼åæ´æ° 卿è¿çä¼åä¸ï¼æä»¬è¿ä¸æ¥æ¹è¿äºç³»ç»æ§è½åç¨³å®æ§ï¼ 1. **éè´§åæ°æ®å¤çä¼å** - å®ç°äº XkyService.GetSaveDetail() æ¹æ³çåæ¹å¤ç - æ¯æ¹å¤ç10æ¡éè´§åæ°æ®ï¼åå°å åå ç¨ - å¢å¼ºäºå¼å¸¸å¤çï¼åæ¡æ°æ®å¼å¸¸ä¸ä¼å½±åæ´æ¹å¤ç 2. **弿¥ä»»å¡å¤çå¢å¼º** - 为 DeliveryNoticeService æ·»å äº @Async 注解ç弿¥å¤çæ¹æ³ - å®ç°äº processAsyncBatch æ¹æ³ï¼æ¯æå¹¶è¡å¤ç夿¹æ°æ® - ä¼åäºæ¥å¿è®°å½ï¼ä¾¿äºé®é¢ææ¥ 3. **é误å¤çæ¹è¿** - ææå ³é®æ¹æ³é½æ·»å äºè¯¦ç»çæ¥å¿è®°å½ - å®ç°äºæ´ç»ç²åº¦çå¼å¸¸æè·åå¤ç - 鲿¢å个任å¡å¤±è´¥å¯¼è´æ´ä¸ªæµç¨ä¸æ ### 弿¥æ§è¡æµç¨ç¤ºä¾ 以䏿¯ä¸ä¸ªå ¸åç弿¥æ§è¡æµç¨ï¼ ``` 主线ç¨: å¼å§å¤ç100æ¡æ°æ® 主线ç¨: å°æ°æ®å为5æ¹ï¼æ¯æ¹20æ¡ ä¸»çº¿ç¨: æäº¤æ¹æ¬¡1å°å¼æ¥çº¿ç¨æ± 主线ç¨: æäº¤æ¹æ¬¡2å°å¼æ¥çº¿ç¨æ± 主线ç¨: æäº¤æ¹æ¬¡3å°å¼æ¥çº¿ç¨æ± 主线ç¨: æäº¤æ¹æ¬¡4å°å¼æ¥çº¿ç¨æ± 主线ç¨: æäº¤æ¹æ¬¡5å°å¼æ¥çº¿ç¨æ± 主线ç¨: å ¨é¨æ°æ®å¤çæäº¤å®æ 弿¥çº¿ç¨1: å¼å§å¤çæ¹æ¬¡1 弿¥çº¿ç¨2: å¼å§å¤çæ¹æ¬¡2 弿¥çº¿ç¨3: å¼å§å¤çæ¹æ¬¡3 弿¥çº¿ç¨1: æ¹æ¬¡1å¤ç宿 弿¥çº¿ç¨1: å¼å§å¤çæ¹æ¬¡4 弿¥çº¿ç¨2: æ¹æ¬¡2å¤ç宿 弿¥çº¿ç¨2: å¼å§å¤çæ¹æ¬¡5 弿¥çº¿ç¨3: æ¹æ¬¡3å¤ç宿 弿¥çº¿ç¨1: æ¹æ¬¡4å¤ç宿 弿¥çº¿ç¨2: æ¹æ¬¡5å¤ç宿 ``` è¿ç§æ¹å¼ç¡®ä¿äºä¸»çº¿ç¨ä¸ä¼è¢«é¿æ¶é´é»å¡ï¼åæ¶å åå©ç¨äºç³»ç»èµæºè¿è¡å¹¶è¡å¤çã src/main/java/com/gs/xky/config/AsyncConfig.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,76 @@ package com.gs.xky.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; /** * 弿¥ä»»å¡é 置类 * é ç½®ä¸ç¨çº¿ç¨æ± å¤ç弿¥ä»»å¡ï¼é¿å é»å¡Springé»è®¤çº¿ç¨æ± */ @Configuration @EnableAsync public class AsyncConfig { private static final Logger log = LoggerFactory.getLogger(AsyncConfig.class); /** * é ç½®éè´è®¢å忥任å¡ä¸ç¨çº¿ç¨æ± * ä½¿ç¨æéççº¿ç¨æ°ï¼é¿å èµæºç«äº */ @Bean(name = "purchaseTaskExecutor") public Executor purchaseTaskExecutor() { log.info("å建éè´è®¢å忥任å¡ä¸ç¨çº¿ç¨æ± "); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // æ ¸å¿çº¿ç¨æ°è®¾ç½®ä¸º1ï¼ç¡®ä¿å䏿¶é´åªæä¸ä¸ªéè´åæ¥ä»»å¡å¨æ§è¡ executor.setCorePoolSize(1); // æå¤§çº¿ç¨æ°è®¾ç½®ä¸º2ï¼å 许æéçå¹¶å executor.setMaxPoolSize(2); // éå容é executor.setQueueCapacity(5); // 线ç¨åç§°åç¼ executor.setThreadNamePrefix("purchase-task-"); // æç»çç¥ï¼å½çº¿ç¨æ± 已满æ¶ï¼è°ç¨è çº¿ç¨æ§è¡ä»»å¡ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // çå¾ ææä»»å¡ç»æååå ³éçº¿ç¨æ± executor.setWaitForTasksToCompleteOnShutdown(true); // çå¾ æ¶é´ï¼ç§ï¼ executor.setAwaitTerminationSeconds(60); // åå§åçº¿ç¨æ± executor.initialize(); return executor; } /** * é ç½®éç¨å¼æ¥ä»»å¡çº¿ç¨æ± * ç¨äºå¤çå ¶ä»è½»éçº§å¼æ¥ä»»å¡ */ @Bean(name = "taskExecutor") public Executor taskExecutor() { log.info("å建éç¨å¼æ¥ä»»å¡çº¿ç¨æ± "); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // æ ¸å¿çº¿ç¨æ° executor.setCorePoolSize(5); // æå¤§çº¿ç¨æ° executor.setMaxPoolSize(10); // éå容é executor.setQueueCapacity(25); // 线ç¨åç§°åç¼ executor.setThreadNamePrefix("async-task-"); // æç»çç¥ï¼å½çº¿ç¨æ± 已满æ¶ï¼è°ç¨è çº¿ç¨æ§è¡ä»»å¡ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // åå§åçº¿ç¨æ± executor.initialize(); return executor; } } src/main/java/com/gs/xky/service/DeliveryNoticeService.java
@@ -22,4 +22,11 @@ Integer processMesInvItemArnStatus(String factory, String company, String userCode, Long id); void processMesInvItemArnStatusAsync(List<MesInvItemArn> itemArnMinus); /** * 弿¥å¤ç䏿¹MesInvItemArnæ°æ® * * @param batchItems å½åæ¹æ¬¡çæ°æ® */ void processAsyncBatch(List<MesInvItemArn> batchItems); } src/main/java/com/gs/xky/service/Impl/DeliveryNoticeServiceImpl.java
@@ -16,6 +16,9 @@ import com.gs.xky.service.DeliveryNoticeService; import com.gs.xky.service.MesInvItemArnService; import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,10 +37,9 @@ public class DeliveryNoticeServiceImpl extends ServiceImpl<DeliveryNoticeMapper, DeliveryNotice> implements DeliveryNoticeService { private static final Logger log = LoggerFactory.getLogger(DeliveryNoticeServiceImpl.class); private final DeliveryNoticeDetailService detailService; private final MesInvItemArnService invItemArnService; @Override public boolean saveDeliveryNotice(XkyDetail xkyDetail) { @@ -114,15 +116,59 @@ @Override public void processMesInvItemArnStatusAsync(List<MesInvItemArn> itemArnMinus) { if (itemArnMinus == null || itemArnMinus.isEmpty()) { return; } // è®°å½å¼å§å¤ççæ¥å¿ log.info("ãprocessMesInvItemArnStatusAsyncãå¼å§å¤ç{}æ¡æ°æ®", itemArnMinus.size()); // åæ¹å¤çï¼æ¯æ¹æå¤å¤ç20æ¡æ°æ® int batchSize = 20; int totalSize = itemArnMinus.size(); int batchCount = (totalSize + batchSize - 1) / batchSize; for (int i = 0; i < batchCount; i++) { int fromIndex = i * batchSize; int toIndex = Math.min((i + 1) * batchSize, totalSize); List<MesInvItemArn> batchItems = itemArnMinus.subList(fromIndex, toIndex); log.info("ãprocessMesInvItemArnStatusAsyncãå¤ç第{}æ¹æ°æ®ï¼èå´ï¼{}-{}", i + 1, fromIndex, toIndex); // 弿¥å¤çæ¯æ¹æ°æ® processAsyncBatch(batchItems); } log.info("ãprocessMesInvItemArnStatusAsyncãå ¨é¨æ°æ®å¤çæäº¤å®æ"); } /** * 弿¥å¤ç䏿¹MesInvItemArnæ°æ® * * @param batchItems å½åæ¹æ¬¡çæ°æ® */ @Async("taskExecutor") public void processAsyncBatch(List<MesInvItemArn> batchItems) { log.info("ãprocessAsyncBatchã弿¥å¤ç{}æ¡æ°æ®å¼å§", batchItems.size()); processBatch(batchItems); log.info("ãprocessAsyncBatchã弿¥å¤ç{}æ¡æ°æ®å®æ", batchItems.size()); } /** * æ¹éå¤çMesInvItemArnæ°æ® * * @param batchItems å½åæ¹æ¬¡çæ°æ® */ private void processBatch(List<MesInvItemArn> batchItems) { // éåæ¯ä¸ª itemArn itemArnMinus.forEach(itemArn -> { batchItems.forEach(itemArn -> { try { // å¤çæ¯ä¸ª itemArn processMesInvItemArnStatus("1000", "1000", "PL017", itemArn.getId()); Integer result = processMesInvItemArnStatus("1000", "1000", "PL017", itemArn.getId()); log.info("ãprocessBatchãå¤çitemArn: {}, ç»æ: {}", itemArn.getId(), result); } catch (Exception e) { // å¤çå¼å¸¸ï¼ä¾å¦è®°å½æ¥å¿ System.err.println("Error processing itemArn: " + itemArn.getId()); e.printStackTrace(); // å¤çå¼å¸¸ï¼è®°å½è¯¦ç»æ¥å¿ log.error("ãprocessBatchãå¤çitemArn: {} å¼å¸¸: {}", itemArn.getId(), e.getMessage(), e); } }); } src/main/java/com/gs/xky/service/PurchaseService.java
@@ -79,8 +79,35 @@ log.info("ãsyncPurchaseOrderDetailsãè·åå°{}æ¡éè´è®¢åæ°æ®", orderDetails.size()); // å¤çéè´è®¢åæç»æ°æ® orderDetails.forEach(detail -> { // åæ¹å¤çæ°æ®ï¼åå°å åå ç¨ int batchSize = 100; // æ¯æ¹å¤ç100æ¡æ°æ® int totalSize = orderDetails.size(); int batchCount = (totalSize + batchSize - 1) / batchSize; // åä¸åæ´è®¡ç®æ¹æ¬¡æ° for (int i = 0; i < batchCount; i++) { int fromIndex = i * batchSize; int toIndex = Math.min((i + 1) * batchSize, totalSize); log.info("ãsyncPurchaseOrderDetailsãå¤ç第{}æ¹æ°æ®ï¼èå´ï¼{}-{}", i + 1, fromIndex, toIndex); // è·åå½åæ¹æ¬¡çæ°æ® List<PurchaseOrderDetail> batchDetails = orderDetails.subList(fromIndex, toIndex); // å¤çå½åæ¹æ¬¡çæ°æ® processBatch(batchDetails); // æå¨è§¦åGCï¼éæ¾å åï¼è°¨æ 使ç¨ï¼ä» å¨å åç´§å¼ æ¶èèï¼ // System.gc(); } } /** * æ¹éå¤çéè´è®¢åæç»æ°æ® * * @param batchDetails å½åæ¹æ¬¡çéè´è®¢åæç»æ°æ® */ private void processBatch(List<PurchaseOrderDetail> batchDetails) { batchDetails.forEach(detail -> { try { // æ ¹æ®æææ å¿å订åç¶æå¤çä¸åçä¸å¡é»è¾ if (detail.getValidFlag() != null && detail.getValidFlag() == 0) { @@ -113,6 +140,10 @@ // ä¿åSRMéè´è®¢åæç» savePurchaseOrderDetail(detail); // 帮å©GCåæ¶ä¸å使ç¨ç对象 wrapper = null; erpData = null; } catch (Exception e) { log.error("ãsyncPurchaseOrderDetails å¤çå¼å¸¸ã订åå·: {}, 项次: {}, å¼å¸¸: {}", detail.getPoErpNo(), detail.getLineNo(), e.getMessage(), e); src/main/java/com/gs/xky/service/XkyService.java
@@ -42,7 +42,7 @@ public void GetSaveDetail() throws IOException { long currentTimeMillis = System.currentTimeMillis(); long startDate = currentTimeMillis - (20 * 60 * 1000); // è®¡ç® 20 åéåçæ¶é´æ³ long startDate = currentTimeMillis - (30 * 60 * 1000); // è®¡ç® 120 åéåçæ¶é´æ³ XkyCommonParam<BodyParam> param = XkyCommonParam.GetInit(); BodyParam bodyParam = new BodyParam(); @@ -66,24 +66,58 @@ return; } deliveryNoList.forEach(deliveryNo -> { log.info("ãGetSaveDetailãè·åå°{}æ¡éè´§åæ°æ®", deliveryNoList.size()); // åæ¹å¤çæ°æ®ï¼åå°å åå ç¨ int batchSize = 10; // æ¯æ¹å¤ç10æ¡æ°æ® int totalSize = deliveryNoList.size(); int batchCount = (totalSize + batchSize - 1) / batchSize; // åä¸åæ´è®¡ç®æ¹æ¬¡æ° for (int i = 0; i < batchCount; i++) { int fromIndex = i * batchSize; int toIndex = Math.min((i + 1) * batchSize, totalSize); log.info("ãGetSaveDetailãå¤ç第{}æ¹éè´§åæ°æ®ï¼èå´ï¼{}-{}", i + 1, fromIndex, toIndex); // è·åå½åæ¹æ¬¡çæ°æ® List<XkyEntity> batchDeliveries = deliveryNoList.subList(fromIndex, toIndex); // å¤çå½åæ¹æ¬¡çæ°æ® processBatchDeliveries(batchDeliveries); } log.info("ãGetSaveDetailãææéè´§åå¤ç宿"); } /** * æ¹éå¤çéè´§åæ°æ® * * @param batchDeliveries å½åæ¹æ¬¡çéè´§åæ°æ® */ private void processBatchDeliveries(List<XkyEntity> batchDeliveries) { batchDeliveries.forEach(deliveryNo -> { try { if ("6".equals(deliveryNo.getStatus()) || "0".equals(deliveryNo.getLogisticsStatus())) { log.info("ãGetSaveDetailãç§»é¤éè´§å: {}", deliveryNo.getDeliveryNo()); log.info("ãprocessBatchDeliveriesãç§»é¤éè´§å: {}", deliveryNo.getDeliveryNo()); remove1(deliveryNo); } else if ("1".equals(deliveryNo.getStatus()) && ("2".equals(deliveryNo.getLogisticsStatus()) || "1".equals(deliveryNo.getLogisticsStatus()))) { log.info("ãprocessBatchDeliveriesãå¤çéè´§å: {}, ç©æµç¶æ: {}", deliveryNo.getDeliveryNo(), deliveryNo.getLogisticsStatus()); XkyDetail detail = getDetail(deliveryNo.getDeliveryNo()); deliveryNoticeService.saveDeliveryNotice(detail); List<BarcodeDeliveryNo> barcodeDeliveryNos = GetBarcodeInformation(deliveryNo.getDeliveryNo()); barcodeInformationService.SaveBarcodeInformation(barcodeDeliveryNos, deliveryNo.getDeliveryNo()); //å·²éè¾¾çæèªå¨è½¬æ¢ä¸ºMESå°è´§å if ("2".equals(deliveryNo.getLogisticsStatus())) { log.info("ãprocessBatchDeliveriesãéè´§åå·²éè¾¾ï¼æ§è¡ç¾æ¶: {}", deliveryNo.getDeliveryNo()); deliveryNoticeService.callPdaReceiptBtn("éè´§åç¾æ¶[BTNOK[PL017[" + deliveryNo.getDeliveryNo(), ""); } } } catch (IOException e) { log.error("ãGetSaveDetail å¤çå¼å¸¸ãéè´§å: {}, å¼å¸¸: {}", deliveryNo.getDeliveryNo(), e.getMessage(), e); throw new RuntimeException(e); log.error("ãprocessBatchDeliveriesãå¤çéè´§åå¼å¸¸: {}, å¼å¸¸: {}", deliveryNo.getDeliveryNo(), e.getMessage(), e); // 䏿åºå¼å¸¸ï¼é¿å ä¸ä¸ªéè´§åçå¼å¸¸å¯¼è´æ´ä¸ªæ¹æ¬¡å¤±è´¥ } catch (Exception e) { log.error("ãprocessBatchDeliveriesãå¤çéè´§åæªé¢æå¼å¸¸: {}, å¼å¸¸: {}", deliveryNo.getDeliveryNo(), e.getMessage(), e); // 䏿åºå¼å¸¸ï¼é¿å ä¸ä¸ªéè´§åçå¼å¸¸å¯¼è´æ´ä¸ªæ¹æ¬¡å¤±è´¥ } }); } src/main/java/com/gs/xky/task/PurchaseOrderSyncTask.java
@@ -8,6 +8,9 @@ import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; /** * éè´è®¢å忥宿¶ä»»å¡ @@ -18,20 +21,76 @@ private static final Logger log = LoggerFactory.getLogger(PurchaseOrderSyncTask.class); private final PurchaseService purchaseService; private final Executor purchaseTaskExecutor; // æ³¨å ¥ä¸ç¨çº¿ç¨æ± // ç¨äºæ è®°ä»»å¡æ¯å¦æ£å¨æ§è¡ private final AtomicBoolean isRunning = new AtomicBoolean(false); /** * 宿¶æ§è¡éè´è®¢ååæ¥ä»»å¡ * æ¯å¤©12ç¹æ´æ§è¡ä¸æ¬¡ * 设置为12ç¹05åæ§è¡ï¼é¿å ä¸å ¶ä»å®æ¶ä»»å¡å²çª * 使ç¨å¼æ¥æ§è¡ï¼é²æ¢é»å¡å ¶ä»å®æ¶ä»»å¡ */ @Scheduled(cron = "0 5 12 * * ?") public void syncPurchaseOrders() { // 妿任å¡å·²ç»å¨è¿è¡ï¼åè·³è¿æ¬æ¬¡æ§è¡ if (!isRunning.compareAndSet(false, true)) { log.info("ãsyncPurchaseOrdersãä¸ä¸æ¬¡ä»»å¡è¿å¨æ§è¡ä¸ï¼è·³è¿æ¬æ¬¡æ§è¡"); return; } log.info("ãsyncPurchaseOrdersãå¼å§æ§è¡éè´è®¢å忥任å¡"); // 使ç¨ä¸ç¨çº¿ç¨æ± æ§è¡å¼æ¥ä»»å¡ CompletableFuture.runAsync(() -> { try { log.info("ãsyncPurchaseOrdersã弿¥çº¿ç¨å¼å§æ§è¡éè´è®¢å忥"); purchaseService.syncPurchaseOrderDetails(); log.info("ãsyncPurchaseOrdersãéè´è®¢å忥任塿§è¡æå"); } catch (IOException e) { log.error("ãsyncPurchaseOrdersãéè´è®¢å忥任塿§è¡å¼å¸¸: {}", e.getMessage(), e); } finally { // æ 论æåè¿æ¯å¤±è´¥ï¼é½å°è¿è¡ç¶æéç½® isRunning.set(false); log.info("ãsyncPurchaseOrdersãä»»å¡ç¶æå·²éç½®ï¼å¯ä»¥æ¥åæ°çä»»å¡"); } }, purchaseTaskExecutor); // ä¸çå¾ ä»»å¡å®æï¼ç«å³è¿åï¼é¿å é»å¡è°åº¦çº¿ç¨ log.info("ãsyncPurchaseOrdersãéè´è®¢å忥任å¡å·²æäº¤å°å¼æ¥çº¿ç¨æ§è¡"); } /** * æå¨è§¦åéè´è®¢ååæ¥ä»»å¡ * ç¨äºç³»ç»ç®¡çåæå¨è§¦å忥 * * @return 任塿¯å¦å·²æäº¤æ§è¡ */ public boolean manualSyncPurchaseOrders() { // 妿任å¡å·²ç»å¨è¿è¡ï¼åæç»æ¬æ¬¡æ§è¡ if (!isRunning.compareAndSet(false, true)) { log.info("ãmanualSyncPurchaseOrdersãä¸ä¸æ¬¡ä»»å¡è¿å¨æ§è¡ä¸ï¼æç»æ¬æ¬¡æ§è¡"); return false; } log.info("ãmanualSyncPurchaseOrdersãæå¨è§¦åéè´è®¢å忥任å¡"); // 使ç¨ä¸ç¨çº¿ç¨æ± æ§è¡å¼æ¥ä»»å¡ CompletableFuture.runAsync(() -> { try { log.info("ãmanualSyncPurchaseOrdersã弿¥çº¿ç¨å¼å§æ§è¡éè´è®¢å忥"); purchaseService.syncPurchaseOrderDetails(); log.info("ãmanualSyncPurchaseOrdersãéè´è®¢å忥任塿§è¡æå"); } catch (IOException e) { log.error("ãmanualSyncPurchaseOrdersãéè´è®¢å忥任塿§è¡å¼å¸¸: {}", e.getMessage(), e); } finally { // æ 论æåè¿æ¯å¤±è´¥ï¼é½å°è¿è¡ç¶æéç½® isRunning.set(false); log.info("ãmanualSyncPurchaseOrdersãä»»å¡ç¶æå·²éç½®ï¼å¯ä»¥æ¥åæ°çä»»å¡"); } }, purchaseTaskExecutor); return true; } } src/main/java/com/gs/xky/task/ScheduledTasks.java
@@ -8,60 +8,126 @@ import com.gs.xky.entity.MesInvItemArn; import com.gs.xky.service.*; import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @Component @RequiredArgsConstructor public class ScheduledTasks { private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class); private final XkyService xkyService; private final ApiService apiService; private final MesStaffService staffService; private final DeliveryNoticeService deliveryNoticeService; private final MesInvItemArnService invItemArnService; private final Executor taskExecutor; // æ³¨å ¥éç¨çº¿ç¨æ± // ç¨äºæ è®°å任塿¯å¦æ£å¨æ§è¡ private final AtomicBoolean isDeviceDataRunning = new AtomicBoolean(false); private final AtomicBoolean isCompensateRunning = new AtomicBoolean(false); private final AtomicBoolean isDingTalkRunning = new AtomicBoolean(false); /** * æ¯äºåéæ§è¡ä¸æ¬¡ * è·åè®¾å¤æè¿ç䏿¡è®°å½ * * @return void * @author tjx * @description TODO * @date 2024/9/27 21:48 */ @Scheduled(cron = "0 0/5 * * * ?") public void getDeviceRealTimeData() throws IOException { xkyService.GetSaveDetail(); public void getDeviceRealTimeData() { // 妿任å¡å·²ç»å¨è¿è¡ï¼åè·³è¿æ¬æ¬¡æ§è¡ if (!isDeviceDataRunning.compareAndSet(false, true)) { log.info("ãgetDeviceRealTimeDataãä¸ä¸æ¬¡ä»»å¡è¿å¨æ§è¡ä¸ï¼è·³è¿æ¬æ¬¡æ§è¡"); return; } log.info("ãgetDeviceRealTimeDataãå¼å§è·å设å¤å®æ¶æ°æ®"); // 使ç¨å¼æ¥æ§è¡ï¼é¿å é»å¡è°åº¦çº¿ç¨ CompletableFuture.runAsync(() -> { try { xkyService.GetSaveDetail(); log.info("ãgetDeviceRealTimeDataãè·å设å¤å®æ¶æ°æ®æå"); } catch (IOException e) { log.error("ãgetDeviceRealTimeDataãè·å设å¤å®æ¶æ°æ®å¼å¸¸: {}", e.getMessage(), e); } finally { isDeviceDataRunning.set(false); } }, taskExecutor); } /** * 宿¶æ§è¡è¡¥å¿é»è¾ */ @Scheduled(cron = "10 3,8,13,18,23,28,33,38,43,48,53,58 * * * ?") public void compensateMethod() throws IOException { public void compensateMethod() { // 妿任å¡å·²ç»å¨è¿è¡ï¼åè·³è¿æ¬æ¬¡æ§è¡ if (!isCompensateRunning.compareAndSet(false, true)) { log.info("ãcompensateMethodãä¸ä¸æ¬¡ä»»å¡è¿å¨æ§è¡ä¸ï¼è·³è¿æ¬æ¬¡æ§è¡"); return; } log.info("ãcompensateMethodãå¼å§æ§è¡è¡¥å¿é»è¾"); // 使ç¨å¼æ¥æ§è¡ï¼é¿å é»å¡è°åº¦çº¿ç¨ CompletableFuture.runAsync(() -> { try { // è¡¥å¿é»è¾ List<MesInvItemArn> itemArnMinus = invItemArnService.getItemArnMinus(); deliveryNoticeService.processMesInvItemArnStatusAsync(itemArnMinus); log.info("ãcompensateMethodãè¡¥å¿é»è¾æ§è¡æå"); } catch (Exception e) { log.error("ãcompensateMethodãè¡¥å¿é»è¾æ§è¡å¼å¸¸: {}", e.getMessage(), e); } finally { isCompensateRunning.set(false); } }, taskExecutor); } /** * 宿¶è·åééæ°æ® */ @Scheduled(cron = "0 0/53 * * * ?") public void getDinTalkData() throws IOException { public void getDinTalkData() { // 妿任å¡å·²ç»å¨è¿è¡ï¼åè·³è¿æ¬æ¬¡æ§è¡ if (!isDingTalkRunning.compareAndSet(false, true)) { log.info("ãgetDinTalkDataãä¸ä¸æ¬¡ä»»å¡è¿å¨æ§è¡ä¸ï¼è·³è¿æ¬æ¬¡æ§è¡"); return; } log.info("ãgetDinTalkDataãå¼å§è·åééæ°æ®"); // 使ç¨å¼æ¥æ§è¡ï¼é¿å é»å¡è°åº¦çº¿ç¨ CompletableFuture.runAsync(() -> { try { DingTalkParam dingTalkParam = new DingTalkParam(1); DingTalkResponse<EmployeeInfo> employeeInfoDingTalkResponse = apiService.sendListRequest(dingTalkParam, EmployeeInfo.class, "http://192.168.1.64/eHR/eHRExternalService/Service.ashx"); DingTalkResponse<EmployeeInfo> employeeInfoDingTalkResponse = apiService.sendListRequest(dingTalkParam, EmployeeInfo.class, "http://192.168.1.64/eHR/eHRExternalService/Service.ashx"); List<EmployeeInfo> collect = employeeInfoDingTalkResponse.getData().stream() .filter(s -> "é æ¢¦è ï¼æµæ±ï¼ç§ææéå ¬å¸".equals(s.getCUnitName())) .collect(Collectors.toList()); List<EmployeeInfo> collect = employeeInfoDingTalkResponse.getData().stream().filter(s -> "é æ¢¦è ï¼æµæ±ï¼ç§ææéå ¬å¸".equals(s.getCUnitName())).collect(Collectors.toList()); System.out.println(collect.size()); log.info("ãgetDinTalkDataãè·åå°{}æ¡åå·¥æ°æ®", collect.size()); List<List<EmployeeInfo>> partition = ListUtil.partition(collect, 100); partition.forEach(staffService::UpdateStaff); log.info("ãgetDinTalkDataãééæ°æ®å¤ç宿"); } catch (IOException e) { log.error("ãgetDinTalkDataãè·åééæ°æ®å¼å¸¸: {}", e.getMessage(), e); } finally { isDingTalkRunning.set(false); } }, taskExecutor); } } src/test/java/com/gs/xky/XkyApplicationTests.java
@@ -58,7 +58,7 @@ @Test void cs() throws IOException { String str = "2225052002LD;222505200F75;22250520145U;2225052026EA;222505204CR8;222505204XY4;222505205WR8;222505208WCJ;222505209N46;22250520D8HK;22250520DM9W;22250520E8XU;22250520EMT7;22250520F01D;22250520FQ18;22250520J6J7;22250520JAWU;22250520JJTE;22250520JVUT;22250520KYN7;22250520QUQ2;22250520RXRY;22250520UR0E;22250520Y5W9;22250528Y85U;2225052918KK;"; String str = "22250529195E;22250529EQHY;22250529HCM9;222505304W8Q;222505305XRK;22250530F6UC;22250530JQ31;22250531UF8T;222506013N09;222506015051;2225060152A2;2225060152EN;222506015AM7;222506015U07;2225060162K4;222506016C4C;222506017GEM;222506017YTU;222506019RWD;22250601A216;22250601C4C3;22250601GTT8;22250601GUGU;22250601H6Y7;22250601JN9X;22250601JVW5;22250601L6R5;22250601NANG;22250601NHK4;22250601NYAL;22250601Q669;22250601RGJX;22250601VCE2;22250601W6C6;22250601WFK1;22250601WH28;22250601XE2T;22250602M0MU;"; String[] split = str.split(";"); @@ -77,6 +77,12 @@ ApiResponse<XkyDetail> detail = apiService.sendListRequest(param, XkyDetail.class, "https://openapi.xiekeyun.com/delivery/getDetail.json"); XkyDetail deliveryNo = detail.getData(); if (deliveryNo == null) { System.out.println("为空çéè´§åå·" + s); return; } if ("6".equals(deliveryNo.getStatus()) || "0".equals(deliveryNo.getLogisticsStatus())) { XkyEntity xkyEntity = new XkyEntity(); xkyEntity.setDeliveryNo(deliveryNo.getDeliveryNo()); start.bat
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,17 @@ @echo off echo æ£å¨å¯å¨éè´è®¢å管çç³»ç»... echo. REM 设置JVM忰以ä¼åå åä½¿ç¨ set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 REM å¯å¨åºç¨ java %JAVA_OPTS% -jar XkyCollection.jar REM 妿å¯å¨å¤±è´¥ï¼çå¾ ç¨æ·æé®åéåº if %ERRORLEVEL% NEQ 0 ( echo. echo åºç¨å¯å¨å¤±è´¥ï¼è¯·æ£æ¥é误信æ¯ã pause exit /b %ERRORLEVEL% ) start.sh
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,17 @@ #!/bin/bash echo "æ£å¨å¯å¨éè´è®¢å管çç³»ç»..." echo # 设置JVM忰以ä¼åå åä½¿ç¨ JAVA_OPTS="-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" # å¯å¨åºç¨ java $JAVA_OPTS -jar XkyCollection.jar # 妿å¯å¨å¤±è´¥ï¼æ¾ç¤ºéè¯¯ä¿¡æ¯ if [ $? -ne 0 ]; then echo echo "åºç¨å¯å¨å¤±è´¥ï¼è¯·æ£æ¥é误信æ¯ã" exit 1 fi