增加修改客户重新同步功能
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
package com.bms.price.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** Async filter-retry progress for billing tasks (Redis). */
|
||||
public class PrcBillingTaskRetryTask implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String STATUS_PENDING = "PENDING";
|
||||
public static final String STATUS_RUNNING = "RUNNING";
|
||||
public static final String STATUS_SUCCESS = "SUCCESS";
|
||||
public static final String STATUS_FAIL = "FAIL";
|
||||
|
||||
private String taskId;
|
||||
private String status;
|
||||
private int percent;
|
||||
private String message;
|
||||
private int total;
|
||||
private int processed;
|
||||
private int ok;
|
||||
private int fail;
|
||||
private String error;
|
||||
|
||||
public String getTaskId()
|
||||
{
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public void setTaskId(String taskId)
|
||||
{
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public String getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status)
|
||||
{
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public int getPercent()
|
||||
{
|
||||
return percent;
|
||||
}
|
||||
|
||||
public void setPercent(int percent)
|
||||
{
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getTotal()
|
||||
{
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(int total)
|
||||
{
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public int getProcessed()
|
||||
{
|
||||
return processed;
|
||||
}
|
||||
|
||||
public void setProcessed(int processed)
|
||||
{
|
||||
this.processed = processed;
|
||||
}
|
||||
|
||||
public int getOk()
|
||||
{
|
||||
return ok;
|
||||
}
|
||||
|
||||
public void setOk(int ok)
|
||||
{
|
||||
this.ok = ok;
|
||||
}
|
||||
|
||||
public int getFail()
|
||||
{
|
||||
return fail;
|
||||
}
|
||||
|
||||
public void setFail(int fail)
|
||||
{
|
||||
this.fail = fail;
|
||||
}
|
||||
|
||||
public String getError()
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error)
|
||||
{
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.bms.price.domain.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Filter for async batch retry of billing tasks.
|
||||
* Require customerCode + billTime range to avoid full-table resync.
|
||||
*/
|
||||
@Data
|
||||
public class BillingTaskRetryByFilterRequest implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Customer code (exact match) */
|
||||
private String customerCode;
|
||||
/** Bill time start yyyy-MM-dd */
|
||||
private String beginTime;
|
||||
/** Bill time end yyyy-MM-dd */
|
||||
private String endTime;
|
||||
/** Optional: FAILED / WAITING / SUCCESS / ALL; default ALL */
|
||||
private String successStatus;
|
||||
/** Optional batch size; server clamps to 20~200, default 50 */
|
||||
private Integer batchSize;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bms.price.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.bms.price.domain.PrcBillingTask;
|
||||
|
||||
public interface PrcBillingTaskMapper
|
||||
@@ -15,4 +16,16 @@ public interface PrcBillingTaskMapper
|
||||
|
||||
/** CAS: WAITING -> processing claim not needed; writeback SUCCESS/FAILED */
|
||||
int updateBillingResult(PrcBillingTask task);
|
||||
|
||||
/** Count tasks for filter retry (customer + bill_time window). */
|
||||
int countTaskIdsByFilter(PrcBillingTask query);
|
||||
|
||||
/**
|
||||
* Keyset page of task ids only (asc) to avoid loading full rows into memory.
|
||||
* lastTaskId exclusive lower bound; pass 0 for first page.
|
||||
*/
|
||||
List<Long> selectTaskIdsByFilter(
|
||||
@Param("query") PrcBillingTask query,
|
||||
@Param("lastTaskId") Long lastTaskId,
|
||||
@Param("limit") int limit);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.bms.price.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.bms.price.domain.PrcBillingTask;
|
||||
import com.bms.price.domain.PrcBillingTaskRetryTask;
|
||||
import com.bms.price.domain.vo.BillingTaskRetryByFilterRequest;
|
||||
import com.bms.price.domain.vo.BillingTaskSubmitRequest;
|
||||
|
||||
public interface IPrcBillingTaskService
|
||||
@@ -22,4 +24,12 @@ public interface IPrcBillingTaskService
|
||||
* @return task after retry
|
||||
*/
|
||||
PrcBillingTask retryTask(Long taskId);
|
||||
|
||||
/**
|
||||
* Start async filter retry (customer + bill_time). Returns async task id for progress poll.
|
||||
*/
|
||||
String startRetryByFilter(BillingTaskRetryByFilterRequest request);
|
||||
|
||||
/** Poll async filter-retry progress. */
|
||||
PrcBillingTaskRetryTask getRetryByFilterTask(String asyncTaskId);
|
||||
}
|
||||
|
||||
+51
@@ -4,6 +4,7 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -13,7 +14,9 @@ import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.StringUtils;
|
||||
import com.bms.price.config.BillingProperties;
|
||||
import com.bms.price.domain.PrcBillingTask;
|
||||
import com.bms.price.domain.PrcBillingTaskRetryTask;
|
||||
import com.bms.price.domain.PrcOrderBill;
|
||||
import com.bms.price.domain.vo.BillingTaskRetryByFilterRequest;
|
||||
import com.bms.price.domain.vo.BillingTaskSubmitRequest;
|
||||
import com.bms.price.domain.vo.TmsPriceBillRequest;
|
||||
import com.bms.price.domain.vo.TmsPriceQuoteResult;
|
||||
@@ -28,6 +31,7 @@ import com.bms.price.oracle.OracleOrderBillMapper;
|
||||
import com.bms.price.oracle.OracleUpstreamOrderService;
|
||||
import com.bms.price.service.IPrcBillingTaskService;
|
||||
import com.bms.price.service.IPrcOrderBillService;
|
||||
import com.bms.price.task.PrcBillingTaskRetryAsyncRunner;
|
||||
|
||||
@Service
|
||||
public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService
|
||||
@@ -55,6 +59,9 @@ public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService
|
||||
@Autowired
|
||||
private BillingProperties billingProperties;
|
||||
|
||||
@Autowired
|
||||
private PrcBillingTaskRetryAsyncRunner retryAsyncRunner;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public PrcBillingTask submitInbound(BillingTaskSubmitRequest request)
|
||||
@@ -359,6 +366,50 @@ public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService
|
||||
return billingTaskMapper.selectPrcBillingTaskById(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String startRetryByFilter(BillingTaskRetryByFilterRequest request)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ServiceException("request required");
|
||||
}
|
||||
String customerCode = trim(request.getCustomerCode());
|
||||
String beginTime = trim(request.getBeginTime());
|
||||
String endTime = trim(request.getEndTime());
|
||||
if (StringUtils.isEmpty(customerCode))
|
||||
{
|
||||
throw new ServiceException("customerCode required");
|
||||
}
|
||||
if (StringUtils.isEmpty(beginTime) || StringUtils.isEmpty(endTime))
|
||||
{
|
||||
throw new ServiceException("beginTime and endTime required");
|
||||
}
|
||||
PrcBillingTask query = new PrcBillingTask();
|
||||
query.setCustomerCode(customerCode);
|
||||
query.setParams(PrcBillingTaskRetryAsyncRunner.timeParams(beginTime, endTime));
|
||||
String status = trim(request.getSuccessStatus());
|
||||
if (StringUtils.isNotEmpty(status) && !"ALL".equalsIgnoreCase(status))
|
||||
{
|
||||
query.setSuccessStatus(status);
|
||||
}
|
||||
String asyncTaskId = UUID.randomUUID().toString().replace("-", "");
|
||||
retryAsyncRunner.put(asyncTaskId, PrcBillingTaskRetryTask.STATUS_PENDING, 0, "queued",
|
||||
0, 0, 0, 0, null);
|
||||
retryAsyncRunner.run(asyncTaskId, query,
|
||||
PrcBillingTaskRetryAsyncRunner.clampBatch(request.getBatchSize()));
|
||||
return asyncTaskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrcBillingTaskRetryTask getRetryByFilterTask(String asyncTaskId)
|
||||
{
|
||||
if (StringUtils.isEmpty(asyncTaskId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return retryAsyncRunner.get(asyncTaskId.trim());
|
||||
}
|
||||
|
||||
private BillTaskType resolveAutoType(String transferNo, String trackingNo, String orderNo)
|
||||
{
|
||||
PrcOrderBill existed = null;
|
||||
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
package com.bms.price.task;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.bms.common.core.redis.RedisCache;
|
||||
import com.bms.common.utils.StringUtils;
|
||||
import com.bms.price.domain.PrcBillingTask;
|
||||
import com.bms.price.domain.PrcBillingTaskRetryTask;
|
||||
import com.bms.price.enums.BillTaskSuccessStatus;
|
||||
import com.bms.price.mapper.PrcBillingTaskMapper;
|
||||
import com.bms.price.service.IPrcBillingTaskService;
|
||||
|
||||
/**
|
||||
* Async filter-based billing task retry: keyset-page IDs then retry one-by-one.
|
||||
*/
|
||||
@Component
|
||||
public class PrcBillingTaskRetryAsyncRunner
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(PrcBillingTaskRetryAsyncRunner.class);
|
||||
|
||||
public static final String CACHE_KEY_PREFIX = "billing:task:retry:";
|
||||
public static final int TTL_MINUTES = 120;
|
||||
public static final int DEFAULT_BATCH = 50;
|
||||
public static final int MIN_BATCH = 20;
|
||||
public static final int MAX_BATCH = 200;
|
||||
|
||||
@Autowired
|
||||
private PrcBillingTaskMapper billingTaskMapper;
|
||||
|
||||
@Autowired
|
||||
@Lazy
|
||||
private IPrcBillingTaskService billingTaskService;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Async("threadPoolTaskExecutor")
|
||||
public void run(String asyncTaskId, PrcBillingTask query, int batchSize)
|
||||
{
|
||||
int batch = clampBatch(batchSize);
|
||||
try
|
||||
{
|
||||
int total = billingTaskMapper.countTaskIdsByFilter(query);
|
||||
put(asyncTaskId, PrcBillingTaskRetryTask.STATUS_RUNNING, 0, "starting", total, 0, 0, 0, null);
|
||||
if (total <= 0)
|
||||
{
|
||||
put(asyncTaskId, PrcBillingTaskRetryTask.STATUS_SUCCESS, 100, "no tasks", 0, 0, 0, 0, null);
|
||||
return;
|
||||
}
|
||||
long lastTaskId = 0L;
|
||||
int processed = 0;
|
||||
int ok = 0;
|
||||
int fail = 0;
|
||||
while (true)
|
||||
{
|
||||
List<Long> ids = billingTaskMapper.selectTaskIdsByFilter(query, Long.valueOf(lastTaskId), batch);
|
||||
if (ids == null || ids.isEmpty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
for (Long taskId : ids)
|
||||
{
|
||||
if (taskId == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
lastTaskId = taskId.longValue();
|
||||
try
|
||||
{
|
||||
PrcBillingTask task = billingTaskService.retryTask(taskId);
|
||||
if (task != null && BillTaskSuccessStatus.SUCCESS.getCode().equals(task.getSuccessStatus()))
|
||||
{
|
||||
ok++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
fail++;
|
||||
log.warn("filter retry failed taskId={} msg={}", taskId, e.getMessage());
|
||||
}
|
||||
processed++;
|
||||
int percent = Math.min(99, (int) ((processed * 100L) / Math.max(1, total)));
|
||||
put(asyncTaskId, PrcBillingTaskRetryTask.STATUS_RUNNING, percent,
|
||||
"processing " + processed + "/" + total, total, processed, ok, fail, null);
|
||||
}
|
||||
if (ids.size() < batch)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
put(asyncTaskId, PrcBillingTaskRetryTask.STATUS_SUCCESS, 100,
|
||||
"done ok=" + ok + " fail=" + fail, total, processed, ok, fail, null);
|
||||
log.info("billing filter retry done asyncTaskId={} total={} ok={} fail={}",
|
||||
asyncTaskId, total, ok, fail);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("billing filter retry failed asyncTaskId={}", asyncTaskId, e);
|
||||
String msg = e.getMessage();
|
||||
if (StringUtils.isEmpty(msg))
|
||||
{
|
||||
msg = e.getClass().getSimpleName();
|
||||
}
|
||||
put(asyncTaskId, PrcBillingTaskRetryTask.STATUS_FAIL, 100, "failed", 0, 0, 0, 0, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void put(String taskId, String status, int percent, String message,
|
||||
int total, int processed, int ok, int fail, String error)
|
||||
{
|
||||
PrcBillingTaskRetryTask task = new PrcBillingTaskRetryTask();
|
||||
task.setTaskId(taskId);
|
||||
task.setStatus(status);
|
||||
task.setPercent(percent);
|
||||
task.setMessage(message);
|
||||
task.setTotal(total);
|
||||
task.setProcessed(processed);
|
||||
task.setOk(ok);
|
||||
task.setFail(fail);
|
||||
task.setError(error);
|
||||
redisCache.setCacheObject(CACHE_KEY_PREFIX + taskId, task, TTL_MINUTES, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
public PrcBillingTaskRetryTask get(String taskId)
|
||||
{
|
||||
return redisCache.getCacheObject(CACHE_KEY_PREFIX + taskId);
|
||||
}
|
||||
|
||||
public static int clampBatch(Integer batchSize)
|
||||
{
|
||||
int n = batchSize == null ? DEFAULT_BATCH : batchSize.intValue();
|
||||
if (n < MIN_BATCH)
|
||||
{
|
||||
return MIN_BATCH;
|
||||
}
|
||||
if (n > MAX_BATCH)
|
||||
{
|
||||
return MAX_BATCH;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Build MyBatis query params map for begin/end time. */
|
||||
public static Map<String, Object> timeParams(String beginTime, String endTime)
|
||||
{
|
||||
Map<String, Object> params = new HashMap<String, Object>();
|
||||
if (StringUtils.isNotEmpty(beginTime))
|
||||
{
|
||||
params.put("beginTime", beginTime.trim());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(endTime))
|
||||
{
|
||||
params.put("endTime", endTime.trim());
|
||||
}
|
||||
return params;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user