增加上传附件到oss
This commit is contained in:
+23
-39
@@ -7,11 +7,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -145,11 +141,13 @@ public class BmsProductImportAsyncRunner
|
||||
return merged;
|
||||
}
|
||||
|
||||
/** Save preview products in parallel. Each product is its own transaction. */
|
||||
/**
|
||||
* Save preview products sequentially (same psv_id).
|
||||
* Parallel inserts into prc_price_set_detail deadlock on secondary indexes.
|
||||
*/
|
||||
@Async("threadPoolTaskExecutor")
|
||||
public void runApplyPreview(String taskId, CatalogPreviewApplyRequest request)
|
||||
{
|
||||
ExecutorService pool = null;
|
||||
try
|
||||
{
|
||||
Map<String, BmsProduct> meta = new HashMap<String, BmsProduct>();
|
||||
@@ -176,6 +174,8 @@ public class BmsProductImportAsyncRunner
|
||||
}
|
||||
}
|
||||
}
|
||||
// Stable order reduces lock-order inversion if another session writes the same version.
|
||||
jobs.sort((a, b) -> String.valueOf(a.getKey()).compareToIgnoreCase(String.valueOf(b.getKey())));
|
||||
int n = jobs.size();
|
||||
if (n == 0)
|
||||
{
|
||||
@@ -184,36 +184,22 @@ public class BmsProductImportAsyncRunner
|
||||
}
|
||||
put(taskId, BmsProductImportTask.STATUS_RUNNING, 5, "\u6b63\u5728\u4fdd\u5b58 0/" + n, null);
|
||||
Long psvId = request.getPsvId();
|
||||
AtomicInteger done = new AtomicInteger();
|
||||
pool = Executors.newFixedThreadPool(Math.min(4, n));
|
||||
List<Future<?>> futures = new ArrayList<Future<?>>();
|
||||
for (Map.Entry<String, List<BmsProductCountry>> e : jobs)
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
Map.Entry<String, List<BmsProductCountry>> e = jobs.get(i);
|
||||
final String code = e.getKey().trim().toUpperCase(Locale.ROOT);
|
||||
final List<BmsProductCountry> details = e.getValue();
|
||||
final BmsProduct product = meta.get(code);
|
||||
futures.add(pool.submit(new Runnable()
|
||||
applyWithDeadlockRetry(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
applyWithDeadlockRetry(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
productService.applyOneCatalogProduct(psvId, code, product, details);
|
||||
}
|
||||
});
|
||||
int d = done.incrementAndGet();
|
||||
put(taskId, BmsProductImportTask.STATUS_RUNNING, 5 + (90 * d / n),
|
||||
"\u6b63\u5728\u4fdd\u5b58 " + d + "/" + n, null);
|
||||
productService.applyOneCatalogProduct(psvId, code, product, details);
|
||||
}
|
||||
}));
|
||||
}
|
||||
for (Future<?> future : futures)
|
||||
{
|
||||
future.get();
|
||||
});
|
||||
put(taskId, BmsProductImportTask.STATUS_RUNNING, 5 + (90 * (i + 1) / n),
|
||||
"\u6b63\u5728\u4fdd\u5b58 " + (i + 1) + "/" + n, null);
|
||||
}
|
||||
put(taskId, BmsProductImportTask.STATUS_SUCCESS, 100, "\u5df2\u4fdd\u5b58\u5230\u5f85\u751f\u6548\u8349\u7a3f", null);
|
||||
log.info("async product apply preview done, taskId={}, products={}", taskId, Integer.valueOf(n));
|
||||
@@ -229,19 +215,12 @@ public class BmsProductImportAsyncRunner
|
||||
}
|
||||
put(taskId, BmsProductImportTask.STATUS_FAIL, 100, "failed", msg);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pool != null)
|
||||
{
|
||||
pool.shutdownNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** InnoDB rolls the product transaction back on deadlock; start a new one. */
|
||||
private void applyWithDeadlockRetry(Runnable action)
|
||||
{
|
||||
int max = 5;
|
||||
int max = 8;
|
||||
for (int attempt = 1; ; attempt++)
|
||||
{
|
||||
try
|
||||
@@ -258,7 +237,7 @@ public class BmsProductImportAsyncRunner
|
||||
log.warn("product catalog save deadlock, retry {}/{}", Integer.valueOf(attempt), Integer.valueOf(max));
|
||||
try
|
||||
{
|
||||
Thread.sleep(50L * attempt);
|
||||
Thread.sleep(80L * attempt + (long) (Math.random() * 40));
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
@@ -274,17 +253,22 @@ public class BmsProductImportAsyncRunner
|
||||
Throwable cur = ex;
|
||||
while (cur != null)
|
||||
{
|
||||
if (cur instanceof org.springframework.dao.PessimisticLockingFailureException)
|
||||
if (cur instanceof org.springframework.dao.PessimisticLockingFailureException
|
||||
|| cur instanceof org.springframework.dao.CannotAcquireLockException
|
||||
|| cur instanceof org.springframework.dao.DeadlockLoserDataAccessException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
String name = cur.getClass().getName();
|
||||
if (name.indexOf("MySQLTransactionRollbackException") >= 0)
|
||||
if (name.indexOf("MySQLTransactionRollbackException") >= 0
|
||||
|| name.indexOf("DeadlockLoser") >= 0
|
||||
|| name.indexOf("CannotAcquireLock") >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
String msg = cur.getMessage();
|
||||
if (msg != null && msg.indexOf("Deadlock found when trying to get lock") >= 0)
|
||||
if (msg != null && (msg.indexOf("Deadlock found when trying to get lock") >= 0
|
||||
|| msg.indexOf("try restarting transaction") >= 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
+22
-39
@@ -7,11 +7,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -145,11 +141,13 @@ public class BmsRedlineProductImportAsyncRunner
|
||||
return merged;
|
||||
}
|
||||
|
||||
/** Save preview products in parallel. Each product is its own transaction. */
|
||||
/**
|
||||
* Save preview products sequentially (same psv_id).
|
||||
* Parallel inserts into prc_price_set_detail deadlock on secondary indexes.
|
||||
*/
|
||||
@Async("threadPoolTaskExecutor")
|
||||
public void runApplyPreview(String taskId, RedlineCatalogPreviewApplyRequest request)
|
||||
{
|
||||
ExecutorService pool = null;
|
||||
try
|
||||
{
|
||||
Map<String, BmsRedlineProduct> meta = new HashMap<String, BmsRedlineProduct>();
|
||||
@@ -176,6 +174,7 @@ public class BmsRedlineProductImportAsyncRunner
|
||||
}
|
||||
}
|
||||
}
|
||||
jobs.sort((a, b) -> String.valueOf(a.getKey()).compareToIgnoreCase(String.valueOf(b.getKey())));
|
||||
int n = jobs.size();
|
||||
if (n == 0)
|
||||
{
|
||||
@@ -184,36 +183,22 @@ public class BmsRedlineProductImportAsyncRunner
|
||||
}
|
||||
put(taskId, BmsRedlineProductImportTask.STATUS_RUNNING, 5, "\u6b63\u5728\u4fdd\u5b58 0/" + n, null);
|
||||
Long psvId = request.getPsvId();
|
||||
AtomicInteger done = new AtomicInteger();
|
||||
pool = Executors.newFixedThreadPool(Math.min(4, n));
|
||||
List<Future<?>> futures = new ArrayList<Future<?>>();
|
||||
for (Map.Entry<String, List<BmsRedlineProductCountry>> e : jobs)
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
Map.Entry<String, List<BmsRedlineProductCountry>> e = jobs.get(i);
|
||||
final String code = e.getKey().trim().toUpperCase(Locale.ROOT);
|
||||
final List<BmsRedlineProductCountry> details = e.getValue();
|
||||
final BmsRedlineProduct product = meta.get(code);
|
||||
futures.add(pool.submit(new Runnable()
|
||||
applyWithDeadlockRetry(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
applyWithDeadlockRetry(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
productService.applyOneCatalogProduct(psvId, code, product, details);
|
||||
}
|
||||
});
|
||||
int d = done.incrementAndGet();
|
||||
put(taskId, BmsRedlineProductImportTask.STATUS_RUNNING, 5 + (90 * d / n),
|
||||
"\u6b63\u5728\u4fdd\u5b58 " + d + "/" + n, null);
|
||||
productService.applyOneCatalogProduct(psvId, code, product, details);
|
||||
}
|
||||
}));
|
||||
}
|
||||
for (Future<?> future : futures)
|
||||
{
|
||||
future.get();
|
||||
});
|
||||
put(taskId, BmsRedlineProductImportTask.STATUS_RUNNING, 5 + (90 * (i + 1) / n),
|
||||
"\u6b63\u5728\u4fdd\u5b58 " + (i + 1) + "/" + n, null);
|
||||
}
|
||||
put(taskId, BmsRedlineProductImportTask.STATUS_SUCCESS, 100, "\u5df2\u4fdd\u5b58\u5230\u5f85\u751f\u6548\u8349\u7a3f", null);
|
||||
log.info("async redline apply preview done, taskId={}, products={}", taskId, Integer.valueOf(n));
|
||||
@@ -229,19 +214,12 @@ public class BmsRedlineProductImportAsyncRunner
|
||||
}
|
||||
put(taskId, BmsRedlineProductImportTask.STATUS_FAIL, 100, "failed", msg);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pool != null)
|
||||
{
|
||||
pool.shutdownNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** InnoDB rolls the product transaction back on deadlock; start a new one. */
|
||||
private void applyWithDeadlockRetry(Runnable action)
|
||||
{
|
||||
int max = 5;
|
||||
int max = 8;
|
||||
for (int attempt = 1; ; attempt++)
|
||||
{
|
||||
try
|
||||
@@ -258,7 +236,7 @@ public class BmsRedlineProductImportAsyncRunner
|
||||
log.warn("redline catalog save deadlock, retry {}/{}", Integer.valueOf(attempt), Integer.valueOf(max));
|
||||
try
|
||||
{
|
||||
Thread.sleep(50L * attempt);
|
||||
Thread.sleep(80L * attempt + (long) (Math.random() * 40));
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
@@ -274,17 +252,22 @@ public class BmsRedlineProductImportAsyncRunner
|
||||
Throwable cur = ex;
|
||||
while (cur != null)
|
||||
{
|
||||
if (cur instanceof org.springframework.dao.PessimisticLockingFailureException)
|
||||
if (cur instanceof org.springframework.dao.PessimisticLockingFailureException
|
||||
|| cur instanceof org.springframework.dao.CannotAcquireLockException
|
||||
|| cur instanceof org.springframework.dao.DeadlockLoserDataAccessException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
String name = cur.getClass().getName();
|
||||
if (name.indexOf("MySQLTransactionRollbackException") >= 0)
|
||||
if (name.indexOf("MySQLTransactionRollbackException") >= 0
|
||||
|| name.indexOf("DeadlockLoser") >= 0
|
||||
|| name.indexOf("CannotAcquireLock") >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
String msg = cur.getMessage();
|
||||
if (msg != null && msg.indexOf("Deadlock found when trying to get lock") >= 0)
|
||||
if (msg != null && (msg.indexOf("Deadlock found when trying to get lock") >= 0
|
||||
|| msg.indexOf("try restarting transaction") >= 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user