Commit 7e3eab32 by pye52

1、整合离线分批机制及服务器上传/写入通知改动

2、完善LogFileMonitor注释
parent bf50cf74
......@@ -37,7 +37,7 @@ import static com.bgycc.smartcanteen.utils.SmartCanteenUtils.TAG;
* "标记成功"状态: 在WebSocket未链接时,"在线支付"订单直接标记为"离线支付",并更新到数据库成功的状态
*/
public class PayOfflineViewModel extends ViewModel {
private static final long TIMEOUT = 5 * 1000;
private static final long TIMEOUT = 10 * 1000;
// 在线支付延迟150ms执行,留出时间给扫码反馈
private static final long REQUEST_DELAY = 150;
private static final long DEFAULT_DELAY = 3 * 1000;
......@@ -91,6 +91,7 @@ public class PayOfflineViewModel extends ViewModel {
private SCWebSocketListener listener = new SCWebSocketListenerAdapter() {
private static final String RESPONSE_MESSAGE = "message";
private static final String RESPONSE_OFFLINE_RESULT = "操作完成";
private static final String RESPONSE_PAY_OFFLINE_RESULT = "PAY_OFFLINE_RESULT";
@Override
public void onOpen(ServerHandshake data) {
......@@ -99,16 +100,23 @@ public class PayOfflineViewModel extends ViewModel {
@Override
public void onMessage(String action, JsonObject obj, String original) {
if (action.equals(RESPONSE_PAY_OFFLINE_RESULT)) {
// 离线订单已写入到服务器数据库,可以标记为支付成功
LogUtils.d(TAG, "离线支付结果响应: " + original);
cancelTimeout();
ResponseRunnable runnable = new ResponseRunnable(original);
SCTaskExecutor.getInstance().executeOnDiskIO(runnable);
return;
}
String message = "";
if (obj.has(RESPONSE_MESSAGE)) {
message = obj.get(RESPONSE_MESSAGE).getAsString();
}
if (!TextUtils.isEmpty(action) || !message.equals(RESPONSE_OFFLINE_RESULT)) return;
// 离线支付结果需要匹配以下规则:
// 1、没有action
// 2、message为"操作完成"
LogUtils.d(TAG, "离线支付结果响应: " + original);
ResponseRunnable runnable = new ResponseRunnable(original);
// 离线订单只上传到服务器,未写入到服务器数据库
// 此时只需要更改其uploadTime(保证一定时间内不会频繁发送到服务器)
UpdateUploadTimeRunnable runnable = new UpdateUploadTimeRunnable();
SCTaskExecutor.getInstance().executeOnDiskIO(runnable);
}
};
......@@ -128,7 +136,7 @@ public class PayOfflineViewModel extends ViewModel {
int result = payDataRepository.updatePayData(payData);
if (result <= 0) {
payOfflineState.postValue(new PayOfflineState(PayOfflineState.MARK_FAILED));
LogUtils.w(TAG, "WebSocket未链接, 订单标记失败: " + payData.toString());
LogUtils.w(TAG, "WebSocket未链接, 订单标记失败: " + payData.toString());
return;
}
payOfflineState.postValue(new PayOfflineState(PayOfflineState.MARK));
......@@ -143,18 +151,19 @@ public class PayOfflineViewModel extends ViewModel {
}
private class RequestRunnable implements Runnable {
// 离线支付每一次上传的订单量(若上传数据量过大服务器会拒绝)
private static final int PAY_OFFLINE_PER_LIMIT = 10;
@Override
public void run() {
long currentTime = System.currentTimeMillis();
List<PayData> payData = payDataRepository.queryPayOfflineData(currentTime, PAY_OFFLINE_PER_LIMIT);
if (payData == null || payData.isEmpty()) {
// 获取需要离线支付的订单
List<PayData> payOfflineData = payDataRepository.queryPayOfflineData(currentTime, PAY_OFFLINE_PER_LIMIT);
if (payOfflineData == null || payOfflineData.isEmpty()) {
cancelTimeout();
payRequest = null;
LogUtils.d(TAG, "所有离线订单处理完毕");
return;
}
payRequest = new PayRequest(deviceSN, payData);
payRequest = new PayRequest(deviceSN, payOfflineData);
String requestStr = gson.toJson(payRequest);
payOfflineState.postValue(new PayOfflineState(PayOfflineState.SEND, requestStr));
SCWebSocketClient.getInstance().send(requestStr);
......@@ -162,6 +171,28 @@ public class PayOfflineViewModel extends ViewModel {
}
}
private class UpdateUploadTimeRunnable implements Runnable {
@Override
public void run() {
if (payRequest == null || payRequest.getData().isEmpty()) {
LogUtils.w(TAG, "后台返回离线支付上传结果,但没有待处理任务");
return;
}
long currentTime = System.currentTimeMillis();
List<PayData> dataList = payRequest.getData();
StringBuilder ids = new StringBuilder();
for (PayData data : dataList) {
ids.append(data.getPayCode())
.append(",");
data.setUploadTime(currentTime);
}
payDataRepository.updatePayData(dataList);
if (ids.length() > 0) {
LogUtils.d(TAG, "已上传的离线支付订单号: " + ids.substring(0, ids.length() - 1));
}
}
}
private class ResponseRunnable implements Runnable {
private String response;
......@@ -171,14 +202,12 @@ public class PayOfflineViewModel extends ViewModel {
@Override
public void run() {
cancelTimeout();
if (payRequest == null || payRequest.getData().isEmpty()) {
LogUtils.w(TAG, "后台返回离线支付结果,但没有待处理任务");
payOfflineState.postValue(new PayOfflineState(PayOfflineState.IDLE));
return;
}
// 保存服务器返回的结果
PayResponse payResponse = gson.fromJson(response, PayResponse.class);
payOfflineState.postValue(new PayOfflineState(PayOfflineState.SUCCESS, payResponse.getMessage()));
long lastInsertId = payResponseRepository.insertPayResponse(payResponse);
......@@ -186,18 +215,18 @@ public class PayOfflineViewModel extends ViewModel {
LogUtils.w(TAG, "离线支付结果插入数据库失败: " + payResponse.toString());
}
List<PayData> payData = payRequest.getData();
// 设置离线支付订单状态为支付成功
List<PayData> dataList = payRequest.getData();
// 设置所有离线支付订单状态为支付成功
// 同时在日志中记录所有订单的payCode
StringBuilder ids = new StringBuilder();
for (PayData data : payData) {
for (PayData data : dataList) {
ids.append(data.getPayCode())
.append(",");
data.paySuccess();
}
payDataRepository.updatePayData(payData);
payDataRepository.updatePayData(dataList);
if (ids.length() > 0) {
LogUtils.d(TAG, "已上传的离线支付订单号: " + ids.substring(0, ids.length() - 1));
LogUtils.d(TAG, "离线支付订单号: " + ids.substring(0, ids.length() - 1) + " 已保存到服务器数据库");
}
payRequest = null;
......@@ -206,13 +235,10 @@ public class PayOfflineViewModel extends ViewModel {
} catch (Exception ignored) {
} finally {
payOfflineState.postValue(new PayOfflineState(PayOfflineState.IDLE));
// 继续处理下一批离线订单
traversalPayOfflineData();
}
}
}
// 离线订单发送到后台超时后,重置其标志位保存到数据库
private class TimeoutRunnable implements Runnable {
@Override
public void run() {
......@@ -222,6 +248,7 @@ public class PayOfflineViewModel extends ViewModel {
payOfflineState.postValue(new PayOfflineState(PayOfflineState.IDLE));
return;
}
LogUtils.w(TAG, "离线支付超时: 订单已重新标记为离线支付");
List<PayData> payDataList = payRequest.getData();
for (PayData d : payDataList) {
d.payOffline();
......
......@@ -31,27 +31,29 @@ public class LogFileMonitor extends Worker {
while (availableSize < (totalSize * 0.1f)) {
// 当可用小于10%时,删除旧日志文件
List<File> logFiles = LogUtils.getLogFiles();
if (logFiles.isEmpty()) {
LogUtils.w(TAG, "没有日志文件,但内存空间已满");
return Result.success();
}
if (logFiles.size() == 1) {
// 只有一个日志文件时,直接删除
FileUtils.delete(logFiles.get(0));
return Result.success();
} else {
// 有多个文件时,先排序,后删除最旧的两份日志
Collections.sort(logFiles, (f1, f2) -> {
if (f1.lastModified() == f2.lastModified()) {
return 0;
int size = logFiles.size();
switch (size) {
case 0:
LogUtils.w(TAG, "没有日志文件,但内存空间已接近满");
return Result.success();
case 1:
// 只有一个日志文件时,直接删除
FileUtils.delete(logFiles.get(0));
return Result.success();
default:
// 有多个文件时,先排序,后删除最旧的日志
Collections.sort(logFiles, (f1, f2) -> {
if (f1.lastModified() == f2.lastModified()) {
return 0;
}
return (f1.lastModified() > f2.lastModified()) ? 1 : -1;
});
for (File f : logFiles.subList(0, 2)) {
FileUtils.delete(f);
}
return (f1.lastModified() > f2.lastModified()) ? 1 : -1;
});
for (File f : logFiles.subList(0, 2)) {
FileUtils.delete(f);
}
totalSize = FileUtils.getFsTotalSize(logDirPath);
availableSize = FileUtils.getFsAvailableSize(logDirPath);
totalSize = FileUtils.getFsTotalSize(logDirPath);
availableSize = FileUtils.getFsAvailableSize(logDirPath);
break;
}
}
return Result.success();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment