Dal-job — это децентрализованная легковесная распределённая система управления задачами. Она не имеет центрального узла, а код выполняется на различных модулях.
Эта система помогает разработчикам сосредоточиться на бизнес-логике при работе в распределенной среде, не беспокоясь о повторном выполнении задач.
Основные функции:
Пример решения: При получении данных можно использовать случайно сгенерированный уникальный глобальный ключ для получения данных и их обработки.
В распределенной среде, использующей децентрализованную распределенную задачу, следует решить следующие проблемы:* 1. Мы сталкиваемся с возможностью многопоточной среды на одном экземпляре, что требует обеспечения выполнения одной задачи одним потоком. (Это случается редко, так как задачи контролируются своими модулями, обычно один экземпляр машины выполняет одну задачу одним потоком.)
Используется строковый блокировщик базы данных для обеспечения выполнения одной задачи одной машиной в любое время.
Детали: использует [пессимистическую блокировку + проверка состояния задачи + ограничение времени] для реализации выполнения одной задачи одной машиной в условиях многопоточности и многопроцессорности (особенно многопроцессорности).
Используются Quartz + MySQL. Также хорошо интегрируются со Spring. Предоставлены аннотации (@TimedTask) для конфигурации задач.
@Target({TYPE})
@Retention(RUNTIME)
public @interface TimedTask {
String corn();
}
boolean isGlobalSingle() default true; // В распределённой среде, следует ли запускать синглтоном
String desc() default "";
}
Пример планировщика задач:
@TimedTask(corn = "0 0/1 * * * ?", desc = "тестовый job222")
@Service
public class MyTestJob2 implements ExecutableTask {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println(DateTime.now() + "--" + Thread.currentThread().getName() + "---------------doBizJob2222--------");
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (new Random().nextInt() % 2 == 0) {
throw new RuntimeException("biz выполнение MyTestJob2 произошло с ошибкой, xxxxxxxxx");
}
}
}
Dal-job предоставляет встроенную реализацию повторной попытки выполнения задач, что позволяет легко выполнять периодическую повторную попытку для некорректных данных.
Повторная попытка делится на два типа: первый — это предварительная повторная попытка; второй — последняя повторная попытка.
@BeforehandRetry:
/**
* Предварительная компенсация, гарантирующая, что каждое выполнение бизнес-логики имеет запись. Это может привести к снижению производительности.
* @author wzy
* @date 2017-07-14 17:03:45
*/
@Target({METHOD})
@Retention(RUNTIME)
@Inherited
public @interface BeforehandRetry {
/**
* Исключение для повторной попытки, по умолчанию это BizRetryNeedException. Для бизнес-исключений повторная попытка не требуется!
*/
Class<? extends Throwable> retryFor() default BizRetryNeedException.class;
/**
* Максимальное количество повторных попыток
*/
int maxRetryCount() default 3;
}
Пример: com.kvn.dal.core.beforehand_retry.BeforehandRetryBizService.java
@Service
public class BeforehandRetryBizService {
@BeforehandRetry
public String doBiz(Foo foo, String param){
System.out.println("--->isRetryThread:" + ThreadContext.getContext().isRetryThread());
System.out.println("Параметры: Foo=" + JSON.toJSONString(foo) + ", param=" + param);
System.out.println("Выполнение бизнес-логики завершилось с ошибкой >>>>>>>>");
}
}
throw new BizRetryNeedException("Бизнес-операция завершилась ошибкой, требуется повторная попытка! ! !");
}
}
### Повторная попытка после выполнения операции
Повторная попытка после выполнения операции — это ситуация, когда бизнес-операция завершается с ошибкой, а необходимые для повторной попытки данные сохраняются в базе данных (таблица: job_retry). Затем через расписание задач происходит автоматическая повторная попытка.
```Для классов, требующих повторной попытки, можно реализовать интерфейс `IRetrySupport` или наследовать от класса `AbstractRetrySupport`.
Интерфейс `IRetrySupport.java`
>
public interface IRetrySupport {
/**
* Повторная попытка
* @param retryContext контекст повторной попытки
* @return результат повторной попытки: true | false
*/
boolean retry(AfterwardRetryContext retryContext);
}
**Пример реализации:** реализация через интерфейс `com.kvn.dal.core.afterward_retry.AfterwardRetryBizService.java`
>
@Service
public class AfterwardRetryBizService implements IRetrySupport {
@Resource
IJobRetryDao jobRetryDao;
public void executeBiz() {
System.out.println(DateTime.now() + "--" + Thread.currentThread().getName() + "---------------doBizJob2222--------");
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
Foo foo = new Foo(1001, "xxx");
try {
throw new RuntimeException("executeBiz异常,xxxxxxxxx");
} catch (Exception e) {
ArrayList<RetryParam> retryLs = new RetryParamListWrapper().buildRetryParam(foo).buildRetryParam("xxx").buildRetryParam("hehehe").toArrayList();
JobRetry retry = JobRetry.createJobRetry(getClass(), "key001", retryLs);
jobRetryDao.add(retry);
throw e;
}
}
} @Override
public Boolean retry(AfterwardRetryContext retryContext) {
/** Реализация логики повторной попытки */
String retryDataKey = retryContext.getRetryDataKey();
List<RetryParam> paramLs = retryContext.getRetryParamLs();
Foo foo = paramLs.get(0).restoreParam(Foo.class);
String originParam1 = paramLs.get(1).restoreParam(String.class);
String originParam2 = paramLs.get(2).restoreParam(String.class);
// или
Foo foo2 = retryContext.getRetryParamValueMap().get(Foo.class).get(0);
String originParam1_ = retryContext.getRetryParamValueMap().get(String.class).get(0);
String originParam2_ = retryContext.getRetryParamValueMap().get(String.class).get(1);
``````markdown
## Пример: способ наследования класса
`com.kvn.dal.core.afterward_retry.AfterwardRetryBestPracticeService.java`
```java
@Service
public class AfterwardRetryBestPracticeService extends AbstractRetrySupport {
public void executeBiz() {
System.out.println(DateTime.now() + "--" + Thread.currentThread().getName() + "---------------doBizJob2222--------");
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
Foo foo = new Foo(1001, "xxx");
try {
throw new RuntimeException("выполнение executeBiz завершилось ошибкой, xxxxxxxxx");
} catch (Exception e) {
this.retryEnqueue("key001", foo, "hehe", "утро");
throw e; // При возникновении исключения завершаем выполнение бизнес-логики
}
}
@Override
public Boolean retry(AfterwardRetryContext retryContext) {
// Реализация логики повторной попытки
return true;
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )