1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/dromara-gobrs-async

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Индекс ресурсов

Введение в Gobrs-Async

Gobrs-Async — это мощный, гибко настраиваемый фреймворк многопоточной асинхронной параллельной обработки и динамической компоновки с полным цепочным обратным вызовом ошибок, оптимизацией памяти и управлением состояниями. Он предоставляет предприятиям возможность динамического управления задачами в сложных сценариях.

Для решения проблем, связанных с асинхронностью, зависимостью задач и трудностями контроля состояний при работе со сложными сценариями, был создан Gobrs-Async.

Какие проблемы решает

При разработке сложных корпоративных систем часто возникают ситуации, когда требуется обращение к различным данным корпоративных сервисов, что приводит к сложным зависимостям данных. В таких случаях сложность кода увеличивается. Пример такой ситуации представлен ниже: 1.1

Последняя версия

<dependency>
    <groupId>io.github.memorydoc</groupId>
    <artifactId>gobrs-async-starter</artifactId>
    <version>1.2.9-RELEASE</version>
</dependency>

Быстрый старт

Клонировать исходный код Gobrs-Async здесь.Запустить приложение GobrsAsyncExampleApplication модуля Gobrs-Async-Example.

Изменять конфигурацию пула потоков через HTTP GET запрос по адресу: http://localhost:8888/gobrs/testGobrs. Вывод в консоли IntelliJ IDEA:

EService Begin
AService Begin
AService Finish
BService Begin
BService Finish
FService Begin
EService Finish
CService Begin
CService Finish
FService Finish
GService Begin
GService Finish
HService Begin
HService Finish
2022-11-27 19:08:51.080  INFO 61949 --- [nio-8888-exec-1] com.gobrs.async.core.TaskLoader          : 【ProcessTrace】Общее время выполнения: 2536 мс | traceId = 11702850586978176 | 【задача】AService затратил времени: 302 мс【состояние】: успех; ->【задача】BService затратил времени: 0 мс【состояние】: успех; ->【задача】EService затратил времени: 602 мс【состояние】: успех; ->【задача】CService затратил времени: 305 мс【состояние】: успех; ->【задача】FService затратил времени: 2006 мс【состояние】: успех; ->【задача】GService затратил времени: 105 мс【состояние】: успех; ->【задача】HService затратил времени: 102 мс【состояние】: успех;
2551

Процесс выполнения

Из логов можно видеть процесс выполнения всего цикла```sh [ProcessTrace] Общее время выполнения: 2536 мс | traceId = 11702850586978176 | [Задача] Время выполнения AService: 302 мс [Состояние]: Успех; -> [Задача] Время выполнения BService: 0 мс [Состояние]: Успех; -> [Задача] Время выполнения EService: 602 мс [Состояние]: Успех; -> [Задача] Время выполнения CService: 305 мс [Состояние]: Успех; -> [Задача] Время выполнения FService: 2006 мс [Состояние]: Успех; -> [Задача] Время выполнения GService: 105 мс [Состояние]: Успех; -> [Задача] Время выполнения HService: 102 мс [Состояние]: Успех;


* Общее время выполнения: общее время выполнения задач
* traceId: уникальный идентификатор трассировки задач
* время выполнения: время выполнения отдельной задачи### Конфигурационный файл
```yaml
server:
  port: 8888 # порт: 8888
gobrs:
  async:
    config:
      правила:
        # правила являются массивами с множеством правил
        - имя: "общий"
          содержание: "AService->BService->FService->GService->HService;EService->CService;AService"
          прерывание_задачи: false # прерывать основной поток при локальном сбое по умолчанию false
          транзакция: false

Отключение Gobrs-Async

server:
  port: 8888 # порт: 8080
gobrs:
  async:
    включено: false # отключение движка компоновки
    правила:
      # поддерживает несколько пространств имён
      - имя: "ruleName" # название правила
        содержание: "AService->BService,CService,FService; BService->FService,GService;"
      - имя: "azh"
        содержание: "AService->BService,CService,FService; BService->FService,GService;"
    прерывание_задачи: false # прерывать основной поток при локальном сбое

Пример полной конфигурации```yaml

gobrs: async: config: правила: # правила являются массивами с множеством правил - имя: "общий" содержание: "AService->BService->FService->GService->HService;EService->CService;AService" прерывание_задачи: true # прерывать основной поток при локальном сбое по умолчанию false транзакция: true - имя: "любоеУсловиеОбщий" содержание: "AServiceCondition,BServiceCondition,CServiceCondition->DServiceCondition" конфигЛога: логируемоВремяВыполнения: false # включить вывод времени выполнения задач в логах уровня ошибки по умолчанию true логируемоСбои: true # включить вывод сообщений об ошибках задач по умолчанию true # AServiceCondition, BServiceCondition, CServiceCondition — задачи, одна из которых должна вернуть true для продолжения выполнения - имя: "любоеУсловиеПравило" содержание: "AServiceCondition,BServiceCondition,CServiceCondition->DServiceCondition:любоеУсловие"

``````markdown
        - name: "anyConditionRuleAppend"
          content: "AServiceCondition,BServiceCondition,CServiceCondition->DServiceCondition:anyCondition->EServiceCondition"
``````markdown
        # Официальный сценарий 1 https://async.sizegang.cn/pages/2f844b/#%E5%9C%BA%E6%99%AF%E4%B8%80
        - name: "caseOne"
          content: "caseOneTaskA->caseOneTaskB,caseOneTaskC,caseOneTaskD"

        # Официальный сценарий 2 https://async.sizegang.cn/pages/2f844b/#%E5%9C%BA%E6%99%AF%E4%B8%8D
        - name: "caseTwo"
          content: "caseTwoTaskA->caseTwoTaskB->caseTwoTaskC,caseTwoTaskD"
        # Официальный сценарий 3 https://async.sizegang.cn/pages/2f844b/#%E5%9C%BA%E6%99%AF%E4%B8%89
        - name: "caseThree"
          content: "caseThreeTaskA->caseThreeTaskB,caseThreeTaskC,caseFourTaskD->caseThreeTaskG;
                    caseThreeTaskA->caseThreeTaskE,caseThreeTaskF->caseThreeTaskG;"
        # Официальный сценарий 4 https://async.sizegang.cn/pages/2f844b/#%E5%9C%BA%E6%99%AF%E5%9B%9B
        - name: "caseFour"
          content: "caseFourTaskA->caseFourTaskB->caseFourTaskC,caseFourTaskD,caseFourTaskE;
                    caseFourTaskA->caseFourTaskH->caseFourTaskI,caseFourTaskJ,caseFourTaskK;"
          logConfig:
            costLoggable: false # Отключение вывода информации о времени выполнения задач
        # Официальный сценарий 5 https://async.sizegang.cn/pages/2f844b/#%E5%9C%BA%E6%99%AF%E4%BA%94
        - name: "caseFive"
          content: "caseFourTaskA,caseFourTaskB,caseFourTaskC->caseFourTaskD:any:exclusive" # any — выполнение задачи D после завершения любого из A, B или C
          # exclusive — предотвращает выполнение незавершенных задач после завершения задачи D
server:
  port: 9999 # Порт: 9999


## Конфигурационный файл расположения
Если разработчики используют большое количество конфигураций, то совместное использование с конфигурационными файлами Spring Boot может создать избыточность. В этом случае можно создать конфигурационные файлы в директории `resources/config`, поддерживаются следующие варианты:
```* `gobrs.yaml`
* `gobrs.yml`
* `gobrs.properties`

## Структура правил

### Название правила name
Объект правила состоит из двух частей:
* Название правила
* Содержание правила

**Название правила** (name) представляет собой уникальный идентификатор правила: используется при запуске задач через триггер.

### Содержание правила content
**Содержание правила** (content) является основной частью для парсинга правил управления. В зависимости от различных сценариев выполнения задач, конфигурация правил также будет отличаться, но она не будет слишком сложной. Подробные сценарии конфигурации представлены ниже.

## Конфигурация логов logConfig
* costLogabled — вывод журнала процесса включает время выполнения, цепочку вызовов и т.д.
* errLogabled — вывод журнала ошибок выполнения задачи

:::tip Подсказка
Рассмотрим несколько сценариев, после чего вы сможете самостоятельно понять правила конфигурации.

**Примечание:** В нижеследующих конфигурациях A, B, C представляют собой имена бинов Spring для динамических задач, которые можно определить с помощью `<code>@Task("xxx")</code>`. ruleName1 представляет имя правила,
:::## Обработка исключений
При настройке конфигурации задачи `task-interrupt`, некоторые разработчики не хотят, чтобы исключения при выполнении задач были упакованы **gobrs-async**. Они предпочитают самостоятельно обрабатывать исключения, выполняя различные действия в зависимости от типа исключения. Для этого можно использовать конфигурацию
вывода исключений: `catchable`
```yaml
    - name: "stopAsyncRule"
      content: "stopAsyncTaskA,stopAsyncTaskB,stopAsyncTaskC;stopAsyncTaskD->stopAsyncTaskE->stopAsyncTaskF"
      catchable: true
```## Примеры правил

## Сценарий 1

Как показано на рисунке 1-1

![Сценарий 1](https://kevin-cloud-dubbo.oss-cn-beijing.aliyuncs.com/gobrs-async/type1.png)

**Описание**
После завершения выполнения задачи А продолжаются выполнение Б, В и Д

**Конфигурация**
```yaml
gobrs:
async:
  rules:
    - name: "ruleName1"
      content: "A->B,C,D"

Сценарий 2

Как показано на рисунке 1-2

Сценарий 2

Описание После завершения выполнения задачи А выполняется задача Б, а затем В и Д

Конфигурация

gobrs:
async:
  rules:
    - name: "ruleName1"
      content: "A->B->C,D"

Сценарий 3

Как показано на рисунке 1-3

Сценарий 3

Описание После завершения выполнения задачи А выполняются задачи Б и Е, затем последовательно В, Д и Г для Б, Ф и Г для Е

Конфигурация

gobrs:
async:
  rules:
    - name: "ruleName1"
      content: "A->B->C->D->G;A->E->F->G"

Сценарий 4

Как показано на рисунке 1-4

Сценарий 4

Описание Этот сценарий задач также легко поддерживаются gobrs-async

Конфигурация

gobrs:
async:
  rules:
    - name: "ruleName1"
      content: "A->B->C,D,E;A->H->I,J,K"

Сценарий 5

Как показано на рисунке 1-5

Сценарий 5

Пример 1

Описание После выполнения задач А, Б и В выполняется задача ДКонфигурация

gobrs:
async:
  rules:
    - name: "ruleName1"
      content: "A,B,C->D"

Пример 2

Описание Если любой из задач A, B или C завершается выполнением, то сразу выполняется задача D (выполняет тот, кто быстрее завершил свою задачу, аналогично конкурирующим процессам). Для этого можно использовать ключевые слова конфигурации <code>:any</code>.Конфигурация

gobrs:
async:
  ## :any — это ключевое слово, которое указывает на произвольное выполнение зависимости задачи при её завершении
  правила:
    - имя: "ruleName1"
      содержание: "A,B,C->D:any"

Пример 3

Описание Если любой из задач A, B или C завершается выполнением, то сразу выполняется задача D (выполняет тот, кто быстрее завершил свою задачу, аналогично конкурирующим процессам). Разница с примером 2 заключается в том, что если задача D получает право на выполнение, она прерывает выполнение своих зависимых незавершенных задач (чтобы избежать потери ресурсов и обеспечить нормальное выполнение бизнес-процессов). Для этого можно использовать ключевые слова конфигурации :exclusive.

Конфигурация

gobrs:
async:
  ## :exclusive — это ключевое слово
  правила:
    - имя: "ruleName1"
      содержание: "A,B,C->D:any:exclusive"
```### Пример 4
Похож на пример 2, но имеет некоторые различия. В контексте примера 2 невозможно было бы контролировать последующие задачи на основе успешного или неудачного выполнения конкретной задачи. В примере 2 выполнение происходит строго в соответствии со случайным порядком выполнения потока, то есть тот, кто первым завершает свою задачу, продолжает выполнение. Поэтому, чтобы контролировать выполнение задач на основе условий, таких как метод <code>task</code>, который возвращает `true`, чтобы немедленно выполнить следующую задачу, или вернуть `false`, чтобы прекратить выполнение, используется следующий подход.### Шаг 1: Разработка задачи

(Если вы не знаете, как создать динамическую задачу, прочитайте следующий раздел: **динамическая задача**)
```java
@Override
public Boolean task(Object o, TaskSupport support) {
    try {
        System.out.println("AServiceCondition Begin");
        Thread.sleep(300);
        for (int i1 = 0; i1 < i; i1++) {
            i1 += i1;
        }
        System.out.println("AServiceCondition Finish");
    } catch (InterruptedException e) {
       // логирование
       //e.printStackTrace();
       // возвращаем false, если нет права на выполнение подзадач
       return false;
     
    }
    // возвращаем true, чтобы продолжить выполнение подзадач
    return true;
}

Шаг 2: Конфигурация задачи

gobrs:
async:
  ## :any — это ключевое слово, которое указывает на произвольное выполнение зависимости задачи при её завершении
  правила:
    - имя: "ruleName1"
      содержание: "A,B,C->D:anyCondition"

Обратите внимание

Пример 3 следует за примером 2, так как эти два примера представляют собой объединённую сценарий.

Сводка правил

Конфигурация правил очень похожа на схемы процессов.

  • При вилке задач используется , для разделения различных задач.
  • При запуске потока задач используется -> для разделения потока задач.
  • Каждый поток задач завершается использованием ;.:::tip Если вам неудобно использовать указанные выше конфигурационные символы, вы можете создать свои собственные. В Gobrs-Async это также поддерживается. Конфигурацию можно настроить в соответствии с вашими предпочтениями. Для этого достаточно настроить её в файле application.yml. :::## Как разработать асинхронную задачу

:::warning Подсказка Дойдя до этой точки, вероятно, вы уже нетерпеливо ждете возможности попробовать, как разрабатывается асинхронная задача в Gobrs-Async. Давайте вместе исследуем, как должна быть реализована полная AsyncTask.

:::

Простая задача

  • Создайте бин, который расширяет AsyncTask
  • Отметьте аннотацией @Task

Определение задачи

Чтобы глобально перехватывать задачу, каждую задачу следует пометить специальным идентификатором. Это позволяет различать различные задачи при глобальном перехвате, выполнять различные логики или выводить различные журналы. Например, MQ, мониторинг трассировки и т.д. В Gobrs-Async есть поддержка для этого. Вам просто нужно добавить аннотацию в бин задачи, чтобы сообщить фреймворку имя задачи. То есть глобальный перехватчик задач.

@Task(name = "itemTask")

Здесь AsyncTask<T, V> является параметризованным интерфейсом.

  • T представляет тип параметров задачи.
  • V представляет тип возвращаемого значения задачи.

Например:

/**
 * @program: gobrs-async
 * @ClassName TaskBean
 * @description: Асинхронная задача с параметрами типа Object; возвращаемое значение типа Object
 */
@Task
public class BService extends AsyncTask<Object, Object> {
``````java
    @Override
    public void prepare(Object o) {
        // operations before executing the task
    }

    @Override
    public Object task(Object o, TaskSupport support) {
        String result = getResult(support, AService.class);
        System.out.println("Received result: " + result);
        System.out.println("Executing BService");
        return null;
    }
}
## Conditions for task execution

Conditions for task execution are defined by the method `nessary`. This method checks whether tasks should be executed.

```java
@Override
public boolean nessary(Object o, TaskSupport support) {
    return true;
}

Call upon successful task completion

Upon successful completion of a task, the method onSuccess is called.

@Override
public void onSuccess(TaskSupport support) {

}

Call upon unsuccessful task completion

Upon unsuccessful completion of a task, the method onFail is called.

@Override
public void onFail(TaskSupport support) {

}

Main method for task execution

The main method for task execution is the method task, which implements business logic such as RPC, HTTP, IO and so on, consuming system resources.

@Override
public Object task(Object o, TaskSupport support) {
    // todo business logic
    return null;
}

Obtaining dependent results from tasks

The class TaskSupport provides the method getResult, which allows obtaining dependencies without user intervention.

@Override
public Object task(Object o, TaskSupport support) {
    // Obtain result from AService (task bean)
    String result = getResult(support, AService.class, String.class);
```    return null;
}

Метод getResult принимает три параметра:

  • TaskSupport: основной параметр, необходимый для работы с задачами.
  • Class: тип Java-класса, на котором основан бин зависимости.
  • Class: тип результата.

Определение выполнения задачи

Метод nessary используется для определения того, должна ли задача выполняться. Возвращаемое значение true указывает на то, что задача должна быть выполнена; в противном случае — нет.

Пример использования:

@Override
public boolean necessary(String params, TaskSupport support) {
    // Если параметр равен "cancel", задача не будет выполнена
    if ("cancel".equals(params)) {
        return false;
    }
    return true;
}

Обратный вызов при успешном выполнении задачи

Для выполнения дополнительных действий после успешного выполнения задачи можно использовать метод onSuccess.

@Override
public void onSuccess(TaskSupport support) {
    // Логика успешного выполнения задачи
}

Обратный вызов при неудачном выполнении задачи

Для отправки уведомлений при возникновении ошибок можно использовать метод onFail.

@Override
public void onFail(TaskSupport support, Throwable e) {
    // Логика обработки ошибок
}
``````java
@Override
public void onFail(TaskSupport support) {
    // TODO Логика обратного вызова при неудачном выполнении задачи
}
При выполнении задач могут возникнуть ошибки. Если пользователю требуется возможность повторной попытки при сбое задачи, **Gobrs-Async** предоставляет такую возможность. Для этого достаточно использовать аннотацию <code>@Task(retryCount = 10)</code> в бине задачи, которую нужно запустить с возможностью повторной попытки. Число, указанное после параметра <code>retryCount</code>, указывает количество попыток повторного выполнения.
``````java 
@Component
@Task(retryCount = 10)
public class BService extends AsyncTask<Object, Object>  {
// ...
}

Пример тестового случая

Адрес тестового примера

Результат выполнения

2022-12-09 19:36:35.444  INFO 99720 --- [pool-2-thread-1] c.g.a.test.task.retry.CaseRetryTaskA     : caseRetryTaskA использует поток pool-2-thread-1
CaseRetryTaskA Begin
CaseRetryTaskA End
2022-12-09 19:36:35.458  INFO 99720 --- [pool-2-thread-1] c.g.a.test.task.retry.CaseRetryTaskC     : caseRetryTaskC использует поток pool-2-thread-1
2022-12-09 19:36:35.458  INFO 99720 --- [pool-2-thread-2] c.g.a.test.task.retry.CaseRetryTaskB     : caseRetryTaskB использует поток pool-2-thread-2
CaseRetryTaskC Begin
CaseRetryTaskB Begin
CaseRetryTaskC Finish
CaseRetryTaskB Begin
CaseRetryTaskB Begin
CaseRetryTaskB Begin
CaseRetryTaskB Begin
2022-12-09 19:36:35.475 ERROR 99720 --- [pool-2-thread-2] com.gobrs.async.core.task.AsyncTask      : [traceId:11770907551682560] caseRetryTaskB задача выполнена с ошибкой
```java.lang.ArithmeticException: / by zero
	at com.gobrs.async.test.task.retry.CaseRetryTaskB.task(CaseRetryTaskB.java:27) ~[classes/:na]
	at com.gobrs.async.core.task.AsyncTask.taskAdapter(AsyncTask.java:124) ~[classes/:na]
	at com.gobrs.async.core.TaskActuator.call(TaskActuator.java:145) ~[classes/:na]
	at com.alibaba.ttl.TtlCallable.call(TtlCallable.java:58) [transmittable-thread-local-2.11.2.jar:na]
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [na:1.8.0_251]
	at java.util.concurrent.FutureTask.run(FutureTask.java) [na:1.8.0_251]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_251]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_251]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_251]

## Транзакционные задачи
Пользователи могут иметь бизнес-требования, связанные с транзакциями, такие как сценарий A -> B -> C. В случае, если выполнение C завершается ошибкой, то это должно уведомлять A и B о необходимости отката назад в бизнес-процессах. Такой подход также поддерживается **Gobrs-Async**.Для транзакционных задач требуется наследование от `<code>AsyncTask</code>`. Единственным отличием являются следующие три шага:

Необходимо настроить в файле <code>application.yml</code>

### Конфигурация application.yml

```yaml
gobrs:
  async:
    config:
      rules:
        # правило — массив типов, несколько правил
        - имя: "общее"
          контент: "AService->BService->FService->GService->HService;EService->CService;AService"
          транзакция: true

Объявление аннотаций

Добавьте аннотацию отката на те задачи, где требуется транзакция. Gobrs-Async найдет все задачи до AService в цепочке задач и вызовет метод rollback.

@Task(возврат = true)
public class AService extends AsyncTask<Object, Object> {
 // ...
}

Переопределение метода rollback по умолчанию

// Откат транзакции, конкретная логика отката должна быть реализована самостоятельно. Этот метод является методом по умолчанию и требует переопределения.
@Override
public void rollback(DataContext dataContext) {
    //super.rollback(dataContext);
    //todo откатывать бизнес-логику
}

Примечание

Обязательно используйте аннотацию @Task(возврат = true) над теми задачами, которые могут вызвать исключение Пример из официальной документации

Задачи со временем ожидания

Что такое задачи со временем ожидания? Как следует из названия, это одиночная задача, которая может продолжать своё выполнение или прекращаться в зависимости от установленного времени ожидания. Настройка проста.### Аннотация конфигурации Используйте атрибут timeoutInMilliseconds аннотации @Task для настройки.

  • timeoutInMilliseconds всегда указывается в миллисекундах
package com.gobrs.async.test.task.timeout;
import com.gobrs.async.core.TaskSupport;
import com.gobrs.async.core.anno.Task;
import com.gobrs.async.core.task.AsyncTask;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * Тип A сервис.
 * @program: gobrs-async-starter
 * @description:
 * @author: sizegang
 */
@Slf4j
@Task(timeoutInMilliseconds = 300)
public class CaseTimeoutTaskA extends AsyncTask {```markdown
### Настройка пула прослушивания задач
**Настройка пула прослушивания задач включает количество основных потоков, отслеживающих превышение времени выполнения задач. Подробнее о необходимости этой настройки см. раздел [Причины](#особенности).**
```yaml
gobrs:
  async:
    config:
      правила:
        - имя: "цепочка1"
          содержание: "задачаA->задачаB->задачаC"
      время_ожидания_количество_основных_потоков: 200 # Количество основных потоков

Если настройка не указана, используется значение по умолчанию, рассчитываемое следующим образом:

public static Integer calculateCoreNum() {
    int cpuCoreNum = Runtime.getRuntime().availableProcessors();
    return new BigDecimal(cpuCoreNum).divide(new BigDecimal("0.2")).intValue();
}

Одиночное тестирование

Запустить код### Результат выполнения

2022-12-09 16:51:41.031  INFO 37083 --- [pool-2-thread-1] c.g.a.t.task.timeout.CaseTimeoutTaskA    : CaseTimeoutTaskA использует поток --- pool-2-thread-1
CaseTimeoutTaskA Begin
2022-12-09 16:51:41.355 ERROR 37083 --- [   GobrsTimer-1] com.gobrs.async.core.timer.GobrsTimer    :
```com.gobrs.async.core.common.exception.TimeoutException: задача caseTimeoutTaskA истекло время ожидания```
```ru
2022-12-09 16:51:41.355 ОШБИКА 37083 --- [   GobrsTimer-1] com.gobrs.async.core.timer.GobrsTimer    :
```com.gobrs.async.core.common.exception.TimeoutException: задача caseTimeoutTaskA истекло время ожидания```	в com.gobrs.async.core.TaskLoader$1.tick(TaskLoader.java:394) ~[classes/:na]
	в com.gobrs.async.core.timer.GobrsTimer.lambda$addTimerListener$0(GobrsTimer.java:80) ~[classes/:na]
	в java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_251]
	в java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) ~[na:1.8.0_251]
	в java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) ~[na:1.8.0_251]
	в java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) ~[na:1.8.0_251]
	в java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_251]
	в java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_251]
	в java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_251]

2022-12-09 16:51:41.375  INFO 37083 --- [pool-2-thread-2] c.g.a.t.task.timeout.CaseTimeoutTaskB    : CaseTimeoutTaskB начал работу с использованием потока ---pool-2-thread-2
CaseTimeoutTaskB Начало
CaseTimeoutTaskB Конец
2022-12-09 16:51:41.377  INFO 37083 --- [pool-2-thread-2] c.g.a.t.task.timeout.CaseTimeoutTaskC    : CaseTimeoutTaskC начал работу с использованием потока ---pool-2-thread-2
CaseTimeoutTaskC Начало
CaseTimeoutTaskC Конец
2022-12-09 16:51:43.426  INFO 37083 --- [           main] com.gobrs.async.core.TaskLoader          : 【ProcessTrace】Общее время выполнения: 2413 мс【задача】caseTimeoutTaskA затратила: 312 мс【состояние】:неудача【сообщение об ошибке】: sleep interrupted; ->【задача】caseTimeoutTaskB затратила: 0 мс【состояние】:успех; ->【задача】caseTimeoutTaskC затратила: 2011 мс【состояние】:успех;

```### Особое примечание
* Задачи со временем ожидания не поддерживают переиспользование потоков, так как требуется контроль за превышением времени ожидания для логических проверок. Поддержка переиспользования потоков может привести к прерыванию выполнения задач в переиспользуемых потоках.
* Принцип работы "отключения" и "понижения уровня" основан на методе `Hystrix`. Если вы незнакомы с `Hystrix`, можно обратиться к [анализу принципа работы Hystrix](https://my.oschina.net/13426421702/blog/3071368).
* Из-за планирования потоков, время ожидания может иметь погрешность до 10 мс, которую можно игнорировать!## Переиспользование потоков

Предположим, что в следующей последовательности задач `taskA->taskB,TaskC->taskD->taskE,taskF` минимальное количество потоков, необходимых для завершения всей последовательности, составляет 6 потоков или меньше? Ответ очевиден — всего два потока (кроме основного потока) достаточно для выполнения этой сложной многопоточной последовательности. Почему? В условиях параллельного выполнения, задачи TaskB, TaskC или TaskE, TaskF имеют максимум две задачи, выполняющиеся одновременно. Таким образом, ключевым условием количества используемых потоков является количество **параллельно выполняющихся задач**. Давайте посмотрим, сколько потоков используется в данный момент в gobrs-async.

![ccc](https://kevin-cloud-dubbo.oss-cn-beijing.aliyuncs.com/gobrs-async/4091670739478_.pic.jpg)### Тестовый пример
[Адрес](https://gitee.com/dromara/gobrs-async/blob/master/gobrs-async-test/src/test/java/com/gobrs/async/test/performance/CasePerformance.java)### Результат выполнения
```sh
основной поток использует main
использует main
TaskA
2022-12-11 13:58:22.581  INFO 8039 --- [       main] com.gobrs.async.core.task.AsyncTask      : <11780902254572224> [taskA] выполнение
использует main
TaskC
использует pool-2-thread-1
TaskB
2022-12-11 13:58:22.694  INFO 8039 --- [       main] com.gobrs.async.core.task.AsyncTask      : <11780902254572224> [TaskC] выполнение
2022-12-11 13:58:22.694  INFO 8039 --- [pool-2-thread-1] com.gobrs.async.core.task.AsyncTask      : <11780902254572224> [taskB] выполнение
использует pool-2-thread-1
TaskD
2022-12-11 13:58:22.804  INFO 8039 --- [pool-2-thread-1] com.gobrs.async.core.task.AsyncTask      : <11780902254572224> [taskD] выполнение
использует pool-2-thread-1
использует pool-2-thread-2
TaskE
2022-12-11 13:58:22.909  INFO 8039 --- [pool-2-thread-2] com.gobrs.async.core.task.AsyncTask      : <11780902254572224> [taskE] выполнение
TaskF
2022-12-11 13:58:22.910  INFO 8039 --- [pool-2-thread-1] com.gobrs.async.core.task.AsyncTask      : <11780902254572224> [taskF] выполнение
2022-12-11 13:58:22.913  INFO 8039 --- [       main] com.gobrs.async.core.TaskLoader          : 【ProcessTrace】Общее время затраченное: 440мс | traceId = 11780902254572224 | 【задача】taskA затратил: 103мс【состояние】: успех; ->【задача】taskB затратил: 103мс【состояние】: успех; ->【задача】TaskC затратил: 103мс【состояние】: успех; ->【задача】taskD затратил: 106мс【состояние】: успех; ->【задача】taskE затратил: 101мс【состояние】: успех; ->【задача】taskF затратил: 101мс【состояние】: успех;
затрачено времени 462

Описание

По логам видно, что задача TaskC использовала поток задачи TaskA для выполнения задачи.Поскольку задачи TaskB и TaskC выполняются параллельно, в данный момент требуется создание нового потока для выполнения задачи TaskB. После завершения выполнения задачи TaskB, задача TaskD продолжает использовать поток пула потоков pool-2-thread-1 для выполнения задачи. В этот момент после завершения выполнения задачи TaskC выясняется, что её подзадачи были взяты на выполнение другими потоками, освобожденными после завершения задачи TaskB, поэтому нет необходимости использовать свои собственные потоки для выполнения задач. Аналогичным образом процесс задач продолжается дальше. Весь процесс использует всего три потока (включая основной поток).Редактор сравнил множество многопоточных конкурирующих фреймворков в отрасли, и в настоящее время только gobrs-Async обладает возможностью повторного использования потоков. Конкретные тестовые примеры представлены ниже в разделе о производительности.

Логическая система

Логи, печатающиеся с помощью log.error(getFormattedTraceId(), exception);, автоматически содержат traceId. Метод getFormattedTraceId предоставлен методом AsyncTask.

@Slf4j
@Task(failSubExec = true)
public class BService extends AsyncTask {

    int i = 10000;

    @Override
    public void prepare(Object o) {
        log.info(this.getName() + " использует поток ---" + Thread.currentThread().getName());
    }

    @Override
    public Object task(Object o, TaskSupport support) {
        System.out.println("BService Begin");
        for (int i1 = 0; i1 < i; i1++) {
            i1 += i1;
        }
        try {
            System.out.println(1 / 0);
        } catch (Exception exception) {
            log.error(getFormattedTraceId(), exception);
        }

        System.out.println("BService Finish");
        return null;
    }
}

Включение глобального вывода логов

  • costLogabled: вывод полного пути выполнения задачи
  • errLogabled: включение вывода ошибок задачи (по умолчанию true)
gobrs:
  async:
    config:
      rules:
        - name: "optionalRule"
          content: "caseOptionalTaskA->caseOptionalTaskB->caseOptionalTaskC,caseOptionalTaskD->caseOptionalTaskE->caseOptionalTaskF"
          task-interrupt: false # прерывание основного потока при локальной ошибке (по умолчанию false)
          transaction: false
          logConfig:
            costLogabled: true # включение вывода времени выполнения задачи (по умолчанию true)
            errLogabled: true # включение вывода ошибок задачи (по умолчанию true)

Вывод результатов выполнения задач```sh

CaseOptionalTaskA Задача выполнена CaseOptionalTaskA Задача выполнена успешно 2022-12-11 15:47:32.511 INFO 13458 --- [o-8888-exec-152] com.gobrs.async.core.task.AsyncTask : <11781331511388032> [caseOptionalTaskA] выполнение CaseOptionalTaskB Задача выполнена CaseOptionalTaskB Задача выполнена успешно 2022-12-11 15:47:32.613 INFO 13458 --- [o-8888-exec-152] com.gobrs.async.core.task.AsyncTask : <11781331511388032> [caseOptionalTaskB] выполнение CaseOptionalTaskD Задача выполнена CaseOptionalTaskD Задача выполнена успешно 2022-12-11 15:47:32.718 INFO 13458 --- [o-8888-exec-152] com.gobrs.async.core.task.AsyncTask : <11781331511388032> [caseOptionalTaskD] выполнение 2022-12-11 15:47:32.718 INFO 13458 --- [o-8888-exec-152] com.gobrs.async.core.TaskLoader : 【ProcessTrace】Общее время выполнения: 311мс | traceId = 11781331511388032 | 【задача】caseOptionalTaskA затраты времени: 102мс【состояние】: успех; ->【задача】caseOptionalTaskB затраты времени: 102мс【состояние】: успех; ->【задача】caseOptionalTaskD затраты времени: 105мс【состояние】: успех; затраты времени: 311мс

```## Интеграция с внешними системами логирования

Здесь выбрана система логирования [Tlog](https://tlog.yomahub.com/). Подробное описание использования здесь приведено не будет.

### Интеграция и использование

```java 
/**
 * Запуск приложения
 */
@SpringBootApplication
/**
 * Используется модуль gobrs-async-test для создания задач. Для удобства повторное создание задач не требуется.
 */
@ComponentScan(value = {"com.gobrs.async"})
public class GobrsAsyncExampleApplication {

    /**
     * Tlog - система логирования. Официальный сайт: https://tlog.yomahub.com/
     */
    static {
        AspectLogEnhance.enhance();
    }
```    /**
     * Точка входа в приложение.
     *
     * @param args аргументы командной строки
     */
    public static void main(String[] args) {
        SpringApplication.run(GobrsAsyncExampleApplication.class, args);
    }
}

Дополнительные детали

Для получения более подробной информации о способах интеграции обратитесь к примерам проекта gobrs-async-example или скачайте исходный код. Адрес источника кода

Горячая загрузка правил

По умолчанию в Gobrs-Async правила загружаются всего один раз. Однако могут возникнуть ситуации, когда вам потребуется возможность изменения правил в реальном времени без необходимости перезапуска программы. В таком случае Gobrs-Async также предоставляет такую возможность.

По умолчанию Gobrs-Async использует механизм CopyOnWrite для горячей загрузки правил, что обеспечивает высокую производительность и безопасность многопоточной работы.

// Объект для горячей загрузки правил
@Resource
private RuleThermalLoad ruleThermalLoad;
```// Задача для горячей загрузки правил. Необходимость перезапуска программы отсутствует, достаточно передать правило объекту горячей загрузки.
public void updateRule(Rule rule) {
    // Изменение одного правила
    Rule r = new Rule();
    r.setName("правило_название");
    r.setContent("AService->CService->EService->GService; BService->DService->FService->HService;");
    ruleThermalLoad.load(rule);
    
    // Более масштабируемое изменение нескольких правил одновременно
    List<Rule> updateRules = new ArrayList<>();
    updateRules.add(r);
    // updateRules.add(...);
    ruleThermalLoad.load(updateRules);
}
```### Проверка

Если в логах появится следующий вывод, значит горячая загрузка правил выполнена успешно.
```sh
com.gobrs.async.engine.RuleThermalLoad   : правило тестовое обновление выполнено успешно

При выполнении процесса вы можете вручную остановить выполнение рабочего процесса в определённом бизнес-сценарии. После завершения выполнения триггера задачи, можно использовать результат AsyncResult, чтобы определить различные бизнес-логики.

Gobrs-Async также предоставляет возможность сделать это. Пользователи могут вручную вызвать метод stopAsync внутри метода task асинхронной задачи, передав TaskSupport. Вам не нужно беспокоиться о внутренней реализации, чтобы легко завершить основной процесс. Метод <code>stopAsync</code> имеет два параметра, которые описаны ниже:

  • <code>TaskSupport</code>: параметр, используемый в Gobrs-Async, который можно просто передать дальше.
  • <code>expCode</code>: код состояния прерывания, который может быть пользовательским перечнем значений.
    @Override
    public Map task(DataContext dataContext, TaskSupport support) {
        try {
            // todo выполнение задачи
        } catch (Exception e) {
            // todo обработка различных исключений с возвратом разных кодов прерывания
            if (e instanceof RedirectSimpleException) {
                // прерывание процесса выполнения задачи
                stopAsync(support, PRODUCT_NOT_FOUND);
                return null;
            }
            stopAsync(support, SYSTEM_DEMOTION);
        }
        return null;
    }

После завершения выполнения триггера задачи будет получен объект <code>AsyncResult</code> — результат выполнения процесса задачи. В зависимости от различных кодов прерывания выполняются различные бизнес-логики.

Map<String, Object> params  = new HashMap<>();
// имя процесса задачи, параметры передачи процесса задачи, время ожидания завершения процесса задачи
AsyncResult asyncResult = gobrsAsync.go("ruleName", () -> params, timeOut);

if(asyncResult.getExpCode().equals(100)) {
    // бизнес-логика  Yöntem 1
} else if(asyncResult.getExpCode().equals(200)) {
    // бизнес-логика 2
}

Прерывание подзадач при возникновении ошибки

При выполнении последовательности A->B->C, если A выдает ошибку, то Gobrs-Async по умолчанию прекращает выполнение B и C задач. Однако, если пользователь хочет продолжить выполнение B и C задач, Gobrs-Async предоставляет такую возможность. Для этого достаточно указать параметр failSubExec в аннотации <code>Task</code>. По умолчанию failSubExec=false.

@Service
@Task(failSubExec = true)
public class BService extends AsyncTask<Object, Object> {
// ...
}

Исправленный текст:


После завершения выполнения [триггера задачи](/pages/2f674a/#начало_процесса_выполнения_задачи) будет получен объект `<code>AsyncResult</code>` — результат выполнения процесса задачи.
В зависимости от различных кодов прерывания выполняются различные бизнес-логики.
```java 
Map<String, Object> params  = new HashMap<>();
// имя процесса задачи, параметры передачи процесса задачи, время ожидания завершения процесса задачи
AsyncResult asyncResult = gobrsAsync.go("ruleName", () -> params, timeOut);

if(asyncResult.getExpCode().equals(100)) {
    // бизнес-логика 1
} else if(asyncResult.getExpCode().equals(200)) {
    // бизнес-логика 2
}

Прерывание подзадач при возникновении ошибки

При выполнении последовательности A->B->C, если A выдает ошибку, то Gobrs-Async по умолчанию прекращает выполнение B и C задач. Однако, если пользователь хочет продолжить выполнение B и C задач, Gobrs-Async предоставляет такую возможность. Для этого достаточно указать параметр failSubExec в аннотации <code>Task</code>. По умолчанию failSubExec=false.

@Service
@Task(failSubExec = true)
public class BService extends AsyncTask<Object, Object> {
// ...
}
```## Процесс выполнения задачи со статусами
### Что такое процесс выполнения задачи со статусами?
Это довольно простое понятие. Например, есть четыре задачи: A, B, C и D. Выполнение задачи D зависит от выполнения задач A, B и C. Однако состояние выполнения этих задач (A, B, C) может быть неопределенным во время выполнения.
Как решить проблему, когда требуется принять решение о дальнейших действиях в зависимости от состояния выполнения задач? Например, задачи A, B и C могут вернуть различные состояния выполнения в зависимости от бизнес-логики.
Для решения такой проблемы можно использовать возможности динамического управления состоянием, предоставляемые **Gobrs-Async**.Например: если задача A вернет значение `true`, тогда выполнится задача D, без необходимости следить за выполнением задач B и C. Разница с выполнением обычной задачи заключается в том, что результат должен быть типа `AnyConditionResult`.

```java  
package com.gobrs.async.test.task.condition;

import com.gobrs.async.core.TaskSupport;
import com.gobrs.async.core.anno.Task;
import com.gobrs.async.core.common.domain.AnyConditionResult;
import com.gobrs.async.core.task.AsyncTask;
import org.springframework.stereotype.Component;

/**
 * Тип AService.
 *
 * @program: gobrs-async-starter
 * @ClassName AService
 * @description: тип зависимости задачи
 * AServiceCondition,BServiceCondition,CServiceCondition->DServiceCondition:anyCondition
 * <p>
 * Упрощенная конфигурация
 * <p>
 * A,B,C->D:anyCondition
 * <p>
 * D использует состояние AnyCondition в результате задач A,B,C для принятия решения о продолжении выполнения подзадач.
 * @author: sizegang
 * @create: 2022-03-20
 */
@Task(failSubExec = true)
public class AServiceCondition extends AsyncTask {

    /**
     * .
     */
    int sums = 10000;

    @Override
    public AnyConditionResult<String> task(Object o, TaskSupport support) {
        AnyConditionResult.Builder<String> builder = AnyConditionResult.builder();
        try {
            System.out.println("AServiceCondition Begin");
            Thread.sleep(300);
            for (int i1 = 0; i1 < sums; i1++) {
                i1 += i1;
            }
            System.out.println("AServiceCondition Finish");
        } catch (InterruptedException e) {
            e.printStackTrace();
            //  возврат false при возникновении ошибки
            return builder.setState(false).build();
        }
        return builder.setState(true).build();
    }
}
````AnyConditionResult.Builder<String> builder = AnyConditionResult.builder();` создает по умолчанию объект со значением состояния `true`.

## Пример теста
[Адрес теста](https://gitee.com/dromara/gobrs-async/blob/master/gobrs-async-test/src/test/java/com/gobrs/async/test/CaseAnyCondition.java)

## Результат выполнения
```sh
2022-12-09 17:48:44.676  INFO 58639 --- [           main] com.gobrs.async.core.GobrsPrint          : Успешная загрузка Gobrs-Async
Начало CServiceCondition
Начало BServiceCondition
Начало AServiceCondition
Завершение BServiceCondition
Завершение AServiceCondition
Начало DServiceCondition
Завершение DServiceCondition
2022-12-09 17:48:45.435  INFO 58639 --- [pool-1-thread-1] com.gobrs.async.core.TaskLoader          : ProcessTraceОбщее время затраченное: 334мс | traceId = 11770483512420224 | задачаBServiceCondition затратил времени: 3мссостояние: успех; ->задачаAServiceCondition затратил времени: 305мссостояние: успех; ->задачаDServiceCondition:anyCondition затратил времени: 0мссостояние: успех;
377
gobrs-async выполнение testCondition завершено

Конфигурируемый глобальный обработчик исключений

Если вы хотите, чтобы при выполнении задач в процессе выполнения одной из задач возникло исключение, весь процесс выполнения останавливался. Также можно настроить перехват этого исключения, выполняя оповещение или вывод ошибки при возникновении исключения.

Включение глобального обработчика исключенийНастройте application.yml

gobrs:
  async:
    config:
      rules:
        # Rules are arrays with multiple rules
        - name: "general"
          content: "AService->BService->FService->GService->HService;EService->CService;AService"
          task-interrupt: true # Local exception interrupts the main process by default false
```### Обработчик исключений
Реализуйте интерфейс `<code>AsyncExceptionInterceptor</code>` для создания пользовательского обработчика исключений
```java
/**
 * @program: gobrs-async
 * @ClassName GobrsExceptionInter
 * @description: Обработка прерывания основного процесса
 * @author: sizegang
 * @create: OnClickListener 2022-02-19 22:55
 * @Version OnClickListener 1.0
 **/
@Component
public class GobrsExceptionInter implements AsyncTaskExceptionInterceptor {

    @Override
    public CompletionException exception(Throwable throwable, boolean state) {
        System.out.println("Глобальный обработчик исключений был активирован");
        return new CompletionException(throwable);
    }
}

По умолчанию

По умолчанию Gobrs-Async имеет отключенное состояние глобального обработчика исключений. Если в процессе выполнения одна из задач завершается с ошибкой, то только эта задача будет прекращена, а остальные задачи продолжат выполняться.

Конфигурируемый глобальный обработчик задач

Некоторым пользователям может потребоваться более сложный подход, чем обработка каждой задачи отдельно. Поэтому Gobrs-Async предоставляет возможность для конфигурирования глобального обработчика задач.### Предварительный глобальный обработчик задач Реализуйте интерфейс <code>AsyncTaskPreInterceptor</code> для создания пользовательского предварительного глобального обработчика задач.

/**
 * @program: m-detail
 * @ClassName AsyncTaskPreInterceptor
 * @description:
 * @author: sizegang
 * @create: 2022-03-24
 **/
@Component
public class TaskPreInterceptor implements AsyncTaskPreInterceptor<DataContext> {

    /**
     *
     * @param params Параметры
     * @param taskName Название задачи
     */
    @Override
    public void preProcess(DataContext params, String taskName) {

Конфигурация пост-глобального задачника-интерцептора

Реализуйте интерфейс TaskPostInterceptor, чтобы создать собственный глобальный пост-обработчик задач.```java /**

  • @program: m-detail

  • @ClassName AsyncTaskPostInterceptor

  • @description:

  • @author: sizegang

  • @create: 2022-03-24 / @Component public class TaskPostInterceptor implements AsyncTaskPostInterceptor { / *

    • @param result Результат выполнения задачи
    • @param taskName Название задачи */ @Override public void postProcess(Object result, String taskName) {

    } }


## Настройка фиксированного пула потоков
По умолчанию **Gobrs-Async** использует пул потоков <code>Executors.newCachedThreadPool()</code>. Если вы хотите настроить свой пул потоков, вам потребуется объект <code>GobrsAsyncThreadPoolFactory</code>.

```java
@Configuration
public class ThreadPoolConfig {

    @Autowired
    private GobrsAsyncThreadPoolFactory factory;

    @PostConstruct
    public void gobrsThreadPoolExecutor() {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(300, 500, 30, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
        factory.setThreadPoolExecutor(threadPoolExecutor);
    }
}

Динамическое обновление пула потоков

Иногда разработчики сталкиваются с проблемой изменения пула потоков после запуска приложения. Если ваша компания имеет распределённую систему конфигураций, которая позволяет в реальном времени обновлять конфигурацию пула потоков, то gobrs предоставляет возможность для этого.

Пример использования:

Конфигурация центра конфигураций

{
    "corePoolSize": 210,
    "maxPoolSize": 600,
    "keepAliveTime": 30,
    "capacity": 10000,
    "threadNamePrefix": "m-detail",
    "rejectedExecutionHandler": "CallerRunsPolicy"
}
@Slf4j
@Configuration
public class ThreadPoolConfig {

    @Autowired
    private GobrsAsyncThreadPoolFactory factory;
@Resource
private DUCCConfigService duccConfigService;
}
@PostConstruct
public void gobrsThreadPoolExecutor() {
    // Получаем конфигурацию пула потоков DuccConstant.GOBRS_ASYNC_THREAD_POOL — ключ конфигурации пула потоков в центре конфигураций
    String config = duccConfigService.getString(DuccConstant.GOBRS_ASYNC_THREAD_POOL);
    ThreadPool threadPool = JSONObject.parseObject(config, ThreadPool.class);
}
```        // Создаем пул потоков с помощью конструктора gobrs-async
        ThreadPoolExecutor executor = ThreadPoolBuilder.buildByThreadPool(threadPool);
        factory.setThreadPoolExecutor(executor);
        listenerDucc();
    }

    // Отслеживаем изменения конфигурации пула потоков в центре конфигураций
    private void listenerDucc() {
        duccConfigService.addListener(new DuccListener(DuccConstant.GOBRS_ASYNC_THREAD_POOL, property -> {
            log.warn("Обнаружено изменение конфигурации пула потоков GobrsAsync в DUCC, свойство: {}", JSON.toJSONString(property.getValue()));
            ThreadPool threadPool = JSONObject.parseObject(property.getValue().toString(), ThreadPool.class);
            ThreadPoolExecutor executor = ThreadPoolBuilder.buildByThreadPool(threadPool);
            factory.setThreadPoolExecutor(executor);
            // Успешное обновление пула потоков
            log.warn("Успешное обновление пула потоков GobrsAsync");
        }));
    }---

## Опциональный процесс выполнения
### Настройка задач
```yaml
- name: "optionalRule"
  content: "caseOptionalTaskA->caseOptionalTaskB->caseOptionalTaskC,caseOptionalTaskD->caseOptionalTaskE->caseOptionalTaskF"

Если разработчики хотят выполнять только caseOptionalTaskD, то в цепочке задач нужно выполнить только три задачи: caseOptionalTaskA, caseOptionalTaskB, caseOptionalTaskD. Остальные задачи не требуются.

Способ вызова

Третьим параметром метода gobrsAsync.go() требуется передать множество (Set) имен бинов задач, которые следует выполнить.

    @Test
    public void testOptional() {
        Map<Class, Object> params = new HashMap<>();
        Set<String> options = new HashSet<>();
        options.add("caseOptionalTaskD"); // В множестве options указывается имя бина задачи, которое должно быть выполнено
        AsyncResult asyncResult = gobrsAsync.go("optionalRule", () -> params, options, 300000);
    }
```### Пример тестирования
[Исходный код](https://gitee.com/dromara/gobrs-async/blob/master/gobrs-async-test/src/test/java/com/gobrs/async/test/optional/CaseOptional.java)

### Результат выполнения
```sh 
Выполнение задачи CaseOptionalTaskA
Задача CaseOptionalTaskA выполнена
2022-12-11 15:47:32.511  INFO 13458 --- [o-8888-exec-152] com.gobrs.async.core.task.AsyncTask      : <0><11781331511388032> <11781331511388032> [caseOptionalTaskA] выполнение
Выполнение задачи CaseOptionalTaskB
Задача CaseOptionalTaskB выполнена
2022-12-11 15:47:32.613  INFO 13458 --- [o-8888-exec-152] com.gobrs.async.core.task.AsyncTask      : <0><11781331511388032> <11781331511388032> [caseOptionalTaskB] выполнение
Выполнение задачи CaseOptionalTaskD
Задача CaseOptionalTaskD выполнена
2022-12-11 15:47:32.718  INFO 13458 --- [o-8888-exec-152] com.gobrs.async.core.task.AsyncTask      : <0><11781331511388032> <11781331511388032> [caseOptionalTaskD] выполнение
2022-12-11 15:47:32.718  INFO 13458 --- [o-8888-exec-152] com.gobrs.async.core.TaskLoader          : <0><11781331511388032> ProcessTraceОбщее время выполнения: 311 мс | traceId = 11781331511388032 | задачаcaseOptionalTaskA затраты времени: 102 мссостояние: успех; ->задачаcaseOptionalTaskB затраты времени: OnClickListener мссостояние: успех; ->задачаcaseOptionalTaskD затраты времени: 105 мссостояние: успех;
время выполнения: 311

Применение сценария

При выполнении ISV (компонента ISV JD Cloud) строительства в одном уровне могут существовать несколько компонентов, имеющих различные задачи потока, требующие различное количество входных данных. В этом случае требуется выбор и выполнение задач в процессе организации.Далее приведены примеры организации данных для каждого компонента.

Плагины

Мониторинг

Адаптер SkyWalking

SkyWalking — это платформа полносистемного мониторинга. Поскольку SkyWalking несовместим с многопоточными traceId, gobrs-async предоставляет плагин SkyWalking.

Способ использования

Введение зависимости в pom.xml

<dependency>
    <groupId>io.github.memorydoc</groupId>
    <artifactId>gobrs-async-skywalking-plugin</artifactId>
    <version>1.2.9-RELEASE</version>
</dependency>

Необходимо просто добавить зависимость для идеального соответствия SkyWalking. Не кажется ли вам это волшебством?

Логи

Полносистемный traceId

Как известно всем разработчикам, полносистемный traceId — это уникальный номер, отображаемый в логах для удобной трассировки цепочки. Благодаря этому можно легко отслеживать проблемы в продакшене, что очень удобно.

Способ использования

Введение зависимости в pom.xml

<dependency>
    <groupId>io.github.memorydoc</groupId>
    <artifactId>gobrs-async-trace-plugin</artifactId>
    <version>1.2.9-RELEASE</version>
</dependency>

Необходимо просто добавить зависимость для идеального соответствия SkyWalking. Не кажется ли вам это волшебством?

Статическое внедрение

Необходимо добавить следующий код в запускающий класс SpringBoot

static {
    GobrsLogger.logger();
}

Описание

Плагин логов Gobrs-Async использует Tlog. При возникновении проблем при использовании обратитесь на официальный сайт Tlog.## Вступите в группу для обсуждения Если у вас есть какие-либо замечания относительно этого проекта, добро пожаловать в раздел Issues для обсуждения; QR-код группы действителен семь дней, можно также добавить автора WeChat для вступления в группу.





Контрибуторы

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Описание недоступно Развернуть Свернуть
Apache-2.0
Отмена

Обновления (9)

все

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/dromara-gobrs-async.git
git@api.gitlife.ru:oschina-mirror/dromara-gobrs-async.git
oschina-mirror
dromara-gobrs-async
dromara-gobrs-async
master