Commit 7e3eab32 by pye52

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

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