Browse Source

[Improvement][Monitor] Show master && worker Busy Or Normal Status and Show Commands table list (#15978)

* update

* test

* add monitor enhance ui

* update

* update

* update doc

* fix spotless

* update

* update

* Update dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/DataAnalysisController.java

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/DataAnalysisController.java

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.java

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.xml

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/CommandMapper.java

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* Update dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.xml

Co-authored-by: Wenjun Ruan <wenjun@apache.org>

* update

* fix spotless

* update

---------

Co-authored-by: Wenjun Ruan <wenjun@apache.org>
3.2.2-release-bak
旺阳 6 months ago committed by GitHub
parent
commit
0e5cb664bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 21
      docs/docs/en/guide/monitor.md
  2. 21
      docs/docs/zh/guide/monitor.md
  3. BIN
      docs/img/new_ui/dev/monitor/alert-server.png
  4. BIN
      docs/img/new_ui/dev/monitor/audit-log.jpg
  5. BIN
      docs/img/new_ui/dev/monitor/audit-log.png
  6. BIN
      docs/img/new_ui/dev/monitor/command-list.png
  7. BIN
      docs/img/new_ui/dev/monitor/failure-command-list.png
  8. BIN
      docs/img/new_ui/dev/monitor/master.png
  9. BIN
      docs/img/new_ui/dev/monitor/statistics.png
  10. BIN
      docs/img/new_ui/dev/monitor/worker.png
  11. 54
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/DataAnalysisController.java
  12. 32
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/MonitorController.java
  13. 6
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/DataAnalysisService.java
  14. 20
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/MonitorService.java
  15. 66
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/DataAnalysisServiceImpl.java
  16. 5
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ExecutorServiceImpl.java
  17. 47
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/MonitorServiceImpl.java
  18. 25
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/MonitorControllerTest.java
  19. 5
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ExecuteFunctionServiceTest.java
  20. 4
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/MonitorServiceTest.java
  21. 7
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/CommandMapper.java
  22. 7
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.java
  23. 1
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProcessDefinitionMapper.java
  24. 16
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/CommandMapper.xml
  25. 19
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.xml
  26. 10
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ProcessDefinitionMapper.xml
  27. 3
      dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/CommandMapperTest.java
  28. 1
      dolphinscheduler-registry/dolphinscheduler-registry-api/src/main/java/org/apache/dolphinscheduler/registry/api/enums/RegistryNodeType.java
  29. 4
      dolphinscheduler-ui/src/layouts/content/use-dataList.ts
  30. 1
      dolphinscheduler-ui/src/locales/en_US/menu.ts
  31. 6
      dolphinscheduler-ui/src/locales/en_US/monitor.ts
  32. 1
      dolphinscheduler-ui/src/locales/zh_CN/menu.ts
  33. 6
      dolphinscheduler-ui/src/locales/zh_CN/monitor.ts
  34. 11
      dolphinscheduler-ui/src/router/modules/monitor.ts
  35. 8
      dolphinscheduler-ui/src/service/modules/monitor/index.ts
  36. 31
      dolphinscheduler-ui/src/service/modules/monitor/types.ts
  37. 18
      dolphinscheduler-ui/src/service/modules/projects-analysis/index.ts
  38. 9
      dolphinscheduler-ui/src/service/modules/projects-analysis/types.ts
  39. 43
      dolphinscheduler-ui/src/views/monitor/servers/alert_server/index.module.scss
  40. 189
      dolphinscheduler-ui/src/views/monitor/servers/alert_server/index.tsx
  41. 80
      dolphinscheduler-ui/src/views/monitor/servers/alert_server/node-modal.tsx
  42. 38
      dolphinscheduler-ui/src/views/monitor/servers/alert_server/use-server-node.ts
  43. 24
      dolphinscheduler-ui/src/views/monitor/servers/master/index.tsx
  44. 4
      dolphinscheduler-ui/src/views/monitor/servers/master/use-master.ts
  45. 63
      dolphinscheduler-ui/src/views/monitor/servers/worker/index.tsx
  46. 4
      dolphinscheduler-ui/src/views/monitor/servers/worker/use-worker.ts
  47. 74
      dolphinscheduler-ui/src/views/monitor/statistics/statistics/index.tsx
  48. 233
      dolphinscheduler-ui/src/views/monitor/statistics/statistics/list-command-table.tsx
  49. 237
      dolphinscheduler-ui/src/views/monitor/statistics/statistics/list-error-command-table.tsx

21
docs/docs/en/guide/monitor.md

@ -16,6 +16,12 @@
![worker](../../../img/new_ui/dev/monitor/worker.png) ![worker](../../../img/new_ui/dev/monitor/worker.png)
### Alert Server
- Mainly related to alert server information.
![alert-server](../../../img/new_ui/dev/monitor/alert-server.png)
### Database ### Database
- Mainly the health status of the DB. - Mainly the health status of the DB.
@ -26,18 +32,17 @@
### Statistics ### Statistics
![statistics](../../../img/new_ui/dev/monitor/statistics.png) ![Command Statistics List](../../../img/new_ui/dev/monitor/command-list.png)
Shows the command list in the system. Data is from the `t_ds_command` table.
![Failure Command Statistics List](../../../img/new_ui/dev/monitor/failure-command-list.png)
| **Parameter** | **Description** | Shows the failure command list in the system. Data is from the `t_ds_error_command` table.
|----------------------------------------|----------------------------------------------------|
| Number of commands wait to be executed | Statistics of the `t_ds_command` table data. |
| The number of failed commands | Statistics of the `t_ds_error_command` table data. |
| Number of tasks wait to run | Count the data of `task_queue` in the ZooKeeper. |
| Number of tasks wait to be killed | Count the data of `task_kill` in the ZooKeeper. |
### Audit Log ### Audit Log
The audit log provides information about who accesses the system and the operations made to the system and record related The audit log provides information about who accesses the system and the operations made to the system and record related
time, which strengthen the security of the system and maintenance. time, which strengthen the security of the system and maintenance.
![audit-log](../../../img/new_ui/dev/monitor/audit-log.jpg) ![audit-log](../../../img/new_ui/dev/monitor/audit-log.png)

21
docs/docs/zh/guide/monitor.md

@ -16,6 +16,12 @@
![worker](../../../img/new_ui/dev/monitor/worker.png) ![worker](../../../img/new_ui/dev/monitor/worker.png)
### Alert Server
- 主要是 alert server 的相关信息。
![alert-server](../../../img/new_ui/dev/monitor/alert-server.png)
### Database ### Database
- 主要是 DB 的健康状况 - 主要是 DB 的健康状况
@ -26,15 +32,16 @@
### Statistics ### Statistics
![statistics](../../../img/new_ui/dev/monitor/statistics.png) ![Command Statistics List](../../../img/new_ui/dev/monitor/command-list.png)
展示系统中的命令列表,数据来自`t_ds_command`表。
![Failure Command Statistics List](../../../img/new_ui/dev/monitor/failure-command-list.png)
- 待执行命令数:统计 t_ds_command 表的数据 展示系统中的失败命令列表,数据来自`t_ds_error_command`表。
- 执行失败的命令数:统计 t_ds_error_command 表的数据
- 待运行任务数:统计 Zookeeper 中 task_queue 的数据
- 待杀死任务数:统计 Zookeeper 中 task_kill 的数据
### 审计日志 ### 审计日志
审计日志的记录提供了有关谁访问了系统,以及他或她在给定时间段内执行了哪些操作的信息,对于维护安全都很有用。 审计日志的记录提供了有关谁访问了系统,以及他或她在给定时间段内执行了哪些操作的信息,对于维护安全都很有用。
![audit-log](../../../img/new_ui/dev/monitor/audit-log.jpg) ![audit-log](../../../img/new_ui/dev/monitor/audit-log.png)

BIN
docs/img/new_ui/dev/monitor/alert-server.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
docs/img/new_ui/dev/monitor/audit-log.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

BIN
docs/img/new_ui/dev/monitor/audit-log.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
docs/img/new_ui/dev/monitor/command-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
docs/img/new_ui/dev/monitor/failure-command-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
docs/img/new_ui/dev/monitor/master.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 134 KiB

BIN
docs/img/new_ui/dev/monitor/statistics.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/img/new_ui/dev/monitor/worker.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 139 KiB

54
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/DataAnalysisController.java

@ -20,17 +20,21 @@ package org.apache.dolphinscheduler.api.controller;
import static org.apache.dolphinscheduler.api.enums.Status.COMMAND_STATE_COUNT_ERROR; import static org.apache.dolphinscheduler.api.enums.Status.COMMAND_STATE_COUNT_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.COUNT_PROCESS_DEFINITION_USER_ERROR; import static org.apache.dolphinscheduler.api.enums.Status.COUNT_PROCESS_DEFINITION_USER_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.COUNT_PROCESS_INSTANCE_STATE_ERROR; import static org.apache.dolphinscheduler.api.enums.Status.COUNT_PROCESS_INSTANCE_STATE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.LIST_PAGING_ALERT_GROUP_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUEUE_COUNT_ERROR; import static org.apache.dolphinscheduler.api.enums.Status.QUEUE_COUNT_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.TASK_INSTANCE_STATE_COUNT_ERROR; import static org.apache.dolphinscheduler.api.enums.Status.TASK_INSTANCE_STATE_COUNT_ERROR;
import org.apache.dolphinscheduler.api.dto.CommandStateCount; import org.apache.dolphinscheduler.api.dto.CommandStateCount;
import org.apache.dolphinscheduler.api.exceptions.ApiException; import org.apache.dolphinscheduler.api.exceptions.ApiException;
import org.apache.dolphinscheduler.api.service.DataAnalysisService; import org.apache.dolphinscheduler.api.service.DataAnalysisService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result; import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO; import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO; import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO; import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO;
import org.apache.dolphinscheduler.common.constants.Constants; import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.dao.entity.Command;
import org.apache.dolphinscheduler.dao.entity.ErrorCommand;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import java.util.List; import java.util.List;
@ -148,4 +152,54 @@ public class DataAnalysisController extends BaseController {
Map<String, Integer> stringIntegerMap = dataAnalysisService.countQueueState(loginUser); Map<String, Integer> stringIntegerMap = dataAnalysisService.countQueueState(loginUser);
return Result.success(stringIntegerMap); return Result.success(stringIntegerMap);
} }
/**
* command queue
*
* @param loginUser login user
* @return queue state count
*/
@Operation(summary = "listPendingCommands", description = "LIST_PENDING_COMMANDS")
@Parameters({
@Parameter(name = "searchVal", description = "SEARCH_VAL", schema = @Schema(implementation = String.class)),
@Parameter(name = "pageNo", description = "PAGE_NO", required = true, schema = @Schema(implementation = int.class, example = "1")),
@Parameter(name = "pageSize", description = "PAGE_SIZE", required = true, schema = @Schema(implementation = int.class, example = "20"))
})
@GetMapping("/listCommand")
@ResponseStatus(HttpStatus.OK)
@ApiException(LIST_PAGING_ALERT_GROUP_ERROR)
public Result<PageInfo<Command>> listPaging(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "projectCode", required = false) Long projectCode,
@RequestParam("pageNo") Integer pageNo,
@RequestParam("pageSize") Integer pageSize) {
checkPageParams(pageNo, pageSize);
PageInfo<Command> commandPageInfo =
dataAnalysisService.listPendingCommands(loginUser, projectCode, pageNo, pageSize);
return Result.success(commandPageInfo);
}
/**
* error command
*
* @param loginUser login user
* @return queue state count
*/
@Operation(summary = "listErrorCommand", description = "LIST_ERROR_COMMAND_LIST_PAGING_NOTES")
@Parameters({
@Parameter(name = "searchVal", description = "SEARCH_VAL", schema = @Schema(implementation = String.class)),
@Parameter(name = "pageNo", description = "PAGE_NO", required = true, schema = @Schema(implementation = int.class, example = "1")),
@Parameter(name = "pageSize", description = "PAGE_SIZE", required = true, schema = @Schema(implementation = int.class, example = "20"))
})
@GetMapping("/listErrorCommand")
@ResponseStatus(HttpStatus.OK)
@ApiException(LIST_PAGING_ALERT_GROUP_ERROR)
public Result<PageInfo<ErrorCommand>> listErrorCommand(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam(value = "projectCode", required = false) Long projectCode,
@RequestParam("pageNo") Integer pageNo,
@RequestParam("pageSize") Integer pageSize) {
checkPageParams(pageNo, pageSize);
PageInfo<ErrorCommand> errorCommandPageInfo =
dataAnalysisService.listErrorCommand(loginUser, projectCode, pageNo, pageSize);
return Result.success(errorCommandPageInfo);
}
} }

32
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/MonitorController.java

@ -18,7 +18,6 @@
package org.apache.dolphinscheduler.api.controller; package org.apache.dolphinscheduler.api.controller;
import static org.apache.dolphinscheduler.api.enums.Status.LIST_MASTERS_ERROR; import static org.apache.dolphinscheduler.api.enums.Status.LIST_MASTERS_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.LIST_WORKERS_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_DATABASE_STATE_ERROR; import static org.apache.dolphinscheduler.api.enums.Status.QUERY_DATABASE_STATE_ERROR;
import org.apache.dolphinscheduler.api.exceptions.ApiException; import org.apache.dolphinscheduler.api.exceptions.ApiException;
@ -26,15 +25,16 @@ import org.apache.dolphinscheduler.api.service.MonitorService;
import org.apache.dolphinscheduler.api.utils.Result; import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants; import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.model.Server; import org.apache.dolphinscheduler.common.model.Server;
import org.apache.dolphinscheduler.common.model.WorkerServerModel;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics; import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
@ -56,35 +56,19 @@ public class MonitorController extends BaseController {
private MonitorService monitorService; private MonitorService monitorService;
/** /**
* master list * server list
* *
* @param loginUser login user * @return server list
* @return master list
*/ */
@Operation(summary = "listMaster", description = "MASTER_LIST_NOTES") @Operation(summary = "listServer", description = "SERVER_LIST_NOTES")
@GetMapping(value = "/masters") @GetMapping(value = "/{nodeType}")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ApiException(LIST_MASTERS_ERROR) @ApiException(LIST_MASTERS_ERROR)
public Result<List<Server>> listMaster(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser) { public Result<List<Server>> listServer(@PathVariable("nodeType") RegistryNodeType nodeType) {
List<Server> servers = monitorService.queryMaster(loginUser); List<Server> servers = monitorService.listServer(nodeType);
return Result.success(servers); return Result.success(servers);
} }
/**
* worker list
*
* @param loginUser login user
* @return worker information list
*/
@Operation(summary = "listWorker", description = "WORKER_LIST_NOTES")
@GetMapping(value = "/workers")
@ResponseStatus(HttpStatus.OK)
@ApiException(LIST_WORKERS_ERROR)
public Result<List<WorkerServerModel>> listWorker(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser) {
List<WorkerServerModel> workerServerModels = monitorService.queryWorker(loginUser);
return Result.success(workerServerModels);
}
/** /**
* query database state * query database state
* *

6
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/DataAnalysisService.java

@ -21,9 +21,12 @@ import org.apache.dolphinscheduler.api.dto.CommandStateCount;
import org.apache.dolphinscheduler.api.dto.DefineUserDto; import org.apache.dolphinscheduler.api.dto.DefineUserDto;
import org.apache.dolphinscheduler.api.dto.TaskCountDto; import org.apache.dolphinscheduler.api.dto.TaskCountDto;
import org.apache.dolphinscheduler.api.dto.project.StatisticsStateRequest; import org.apache.dolphinscheduler.api.dto.project.StatisticsStateRequest;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO; import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO; import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO; import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO;
import org.apache.dolphinscheduler.dao.entity.Command;
import org.apache.dolphinscheduler.dao.entity.ErrorCommand;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import java.util.List; import java.util.List;
@ -117,4 +120,7 @@ public interface DataAnalysisService {
*/ */
TaskCountDto countOneTaskStates(User loginUser, Long taskCode); TaskCountDto countOneTaskStates(User loginUser, Long taskCode);
PageInfo<Command> listPendingCommands(User loginUser, Long projectCode, Integer pageNo, Integer pageSize);
PageInfo<ErrorCommand> listErrorCommand(User loginUser, Long projectCode, Integer pageNo, Integer pageSize);
} }

20
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/MonitorService.java

@ -18,9 +18,9 @@
package org.apache.dolphinscheduler.api.service; package org.apache.dolphinscheduler.api.service;
import org.apache.dolphinscheduler.common.model.Server; import org.apache.dolphinscheduler.common.model.Server;
import org.apache.dolphinscheduler.common.model.WorkerServerModel;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics; import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import java.util.List; import java.util.List;
@ -38,20 +38,10 @@ public interface MonitorService {
List<DatabaseMetrics> queryDatabaseState(User loginUser); List<DatabaseMetrics> queryDatabaseState(User loginUser);
/** /**
* query master list * query server list
* *
* @param loginUser login user * @param nodeType RegistryNodeType
* @return master information list * @return server information list
*/ */
List<Server> queryMaster(User loginUser); List<Server> listServer(RegistryNodeType nodeType);
/**
* query worker list
*
* @param loginUser login user
* @return worker information list
*/
List<WorkerServerModel> queryWorker(User loginUser);
List<Server> getServerListFromRegistry(boolean isMaster);
} }

66
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/DataAnalysisServiceImpl.java

@ -27,14 +27,18 @@ import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.exceptions.ServiceException; import org.apache.dolphinscheduler.api.exceptions.ServiceException;
import org.apache.dolphinscheduler.api.service.DataAnalysisService; import org.apache.dolphinscheduler.api.service.DataAnalysisService;
import org.apache.dolphinscheduler.api.service.ProjectService; import org.apache.dolphinscheduler.api.service.ProjectService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO; import org.apache.dolphinscheduler.api.vo.TaskInstanceCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO; import org.apache.dolphinscheduler.api.vo.WorkflowDefinitionCountVO;
import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO; import org.apache.dolphinscheduler.api.vo.WorkflowInstanceCountVO;
import org.apache.dolphinscheduler.common.constants.Constants; import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.enums.AuthorizationType; import org.apache.dolphinscheduler.common.enums.AuthorizationType;
import org.apache.dolphinscheduler.common.enums.CommandType; import org.apache.dolphinscheduler.common.enums.CommandType;
import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.common.utils.DateUtils; import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.dao.entity.Command;
import org.apache.dolphinscheduler.dao.entity.CommandCount; import org.apache.dolphinscheduler.dao.entity.CommandCount;
import org.apache.dolphinscheduler.dao.entity.ErrorCommand;
import org.apache.dolphinscheduler.dao.entity.ExecuteStatusCount; import org.apache.dolphinscheduler.dao.entity.ExecuteStatusCount;
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition; import org.apache.dolphinscheduler.dao.entity.ProcessDefinition;
import org.apache.dolphinscheduler.dao.entity.Project; import org.apache.dolphinscheduler.dao.entity.Project;
@ -71,6 +75,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
/** /**
@ -380,6 +386,66 @@ public class DataAnalysisServiceImpl extends BaseServiceImpl implements DataAnal
return new TaskCountDto(executeStatusCounts); return new TaskCountDto(executeStatusCounts);
} }
@Override
public PageInfo<Command> listPendingCommands(User loginUser, Long projectCode, Integer pageNo, Integer pageSize) {
Page<Command> page = new Page<>(pageNo, pageSize);
if (loginUser.getUserType().equals(UserType.ADMIN_USER)) {
IPage<Command> commandIPage = commandMapper.queryCommandPage(page);
return PageInfo.of(commandIPage);
}
List<Long> workflowDefinitionCodes = getAuthDefinitionCodes(loginUser, projectCode);
if (workflowDefinitionCodes.isEmpty()) {
return PageInfo.of(pageNo, pageSize);
}
IPage<Command> commandIPage =
commandMapper.queryCommandPageByIds(page, new ArrayList<>(workflowDefinitionCodes));
return PageInfo.of(commandIPage);
}
@Override
public PageInfo<ErrorCommand> listErrorCommand(User loginUser, Long projectCode, Integer pageNo, Integer pageSize) {
Page<ErrorCommand> page = new Page<>(pageNo, pageSize);
if (loginUser.getUserType().equals(UserType.ADMIN_USER)) {
IPage<ErrorCommand> commandIPage = errorCommandMapper.queryErrorCommandPage(page);
return PageInfo.of(commandIPage);
}
List<Long> workflowDefinitionCodes = getAuthDefinitionCodes(loginUser, projectCode);
if (workflowDefinitionCodes.isEmpty()) {
return PageInfo.of(pageNo, pageSize);
}
IPage<ErrorCommand> commandIPage =
errorCommandMapper.queryErrorCommandPageByIds(page, new ArrayList<>(workflowDefinitionCodes));
return PageInfo.of(commandIPage);
}
private List<Long> getAuthDefinitionCodes(User loginUser, Long projectCode) {
Set<Integer> projectIds = resourcePermissionCheckService
.userOwnedResourceIdsAcquisition(AuthorizationType.PROJECTS, loginUser.getId(), log);
if (CollectionUtils.isEmpty(projectIds)) {
return Collections.emptyList();
}
List<Long> projectCodes = projectMapper.selectBatchIds(projectIds)
.stream()
.map(Project::getCode)
.collect(Collectors.toList());
if (projectCode != null) {
if (!projectCodes.contains(projectCode)) {
return Collections.emptyList();
}
projectCodes = Collections.singletonList(projectCode);
}
return processDefinitionMapper.queryDefinitionCodeListByProjectCodes(projectCodes);
}
/** /**
* statistics the process definition quantities of a certain person * statistics the process definition quantities of a certain person
* <p> * <p>

5
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ExecutorServiceImpl.java

@ -90,6 +90,7 @@ import org.apache.dolphinscheduler.extract.master.transportor.StreamingTaskTrigg
import org.apache.dolphinscheduler.extract.master.transportor.StreamingTaskTriggerResponse; import org.apache.dolphinscheduler.extract.master.transportor.StreamingTaskTriggerResponse;
import org.apache.dolphinscheduler.extract.master.transportor.WorkflowInstanceStateChangeEvent; import org.apache.dolphinscheduler.extract.master.transportor.WorkflowInstanceStateChangeEvent;
import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; import org.apache.dolphinscheduler.plugin.task.api.TaskConstants;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import org.apache.dolphinscheduler.service.command.CommandService; import org.apache.dolphinscheduler.service.command.CommandService;
import org.apache.dolphinscheduler.service.cron.CronUtils; import org.apache.dolphinscheduler.service.cron.CronUtils;
import org.apache.dolphinscheduler.service.exceptions.CronParseException; import org.apache.dolphinscheduler.service.exceptions.CronParseException;
@ -289,7 +290,7 @@ public class ExecutorServiceImpl extends BaseServiceImpl implements ExecutorServ
private void checkMasterExists() { private void checkMasterExists() {
// check master server exists // check master server exists
List<Server> masterServers = monitorService.getServerListFromRegistry(true); List<Server> masterServers = monitorService.listServer(RegistryNodeType.MASTER);
// no master // no master
if (masterServers.isEmpty()) { if (masterServers.isEmpty()) {
@ -1142,7 +1143,7 @@ public class ExecutorServiceImpl extends BaseServiceImpl implements ExecutorServ
checkValidTenant(tenantCode); checkValidTenant(tenantCode);
checkMasterExists(); checkMasterExists();
// todo dispatch improvement // todo dispatch improvement
List<Server> masterServerList = monitorService.getServerListFromRegistry(true); List<Server> masterServerList = monitorService.listServer(RegistryNodeType.MASTER);
Server server = masterServerList.get(0); Server server = masterServerList.get(0);
StreamingTaskTriggerRequest taskExecuteStartMessage = new StreamingTaskTriggerRequest(); StreamingTaskTriggerRequest taskExecuteStartMessage = new StreamingTaskTriggerRequest();

47
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/MonitorServiceImpl.java

@ -19,7 +19,6 @@ package org.apache.dolphinscheduler.api.service.impl;
import org.apache.dolphinscheduler.api.service.MonitorService; import org.apache.dolphinscheduler.api.service.MonitorService;
import org.apache.dolphinscheduler.common.model.Server; import org.apache.dolphinscheduler.common.model.Server;
import org.apache.dolphinscheduler.common.model.WorkerServerModel;
import org.apache.dolphinscheduler.dao.entity.User; import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics; import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMetrics;
import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMonitor; import org.apache.dolphinscheduler.dao.plugin.api.monitor.DatabaseMonitor;
@ -27,7 +26,6 @@ import org.apache.dolphinscheduler.registry.api.RegistryClient;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType; import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -35,7 +33,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/** /**
* monitor service impl * monitor service impl
@ -61,48 +58,8 @@ public class MonitorServiceImpl extends BaseServiceImpl implements MonitorServic
return Lists.newArrayList(databaseMonitor.getDatabaseMetrics()); return Lists.newArrayList(databaseMonitor.getDatabaseMetrics());
} }
/**
* query master list
*
* @param loginUser login user
* @return master information list
*/
@Override @Override
public List<Server> queryMaster(User loginUser) { public List<Server> listServer(RegistryNodeType nodeType) {
return registryClient.getServerList(RegistryNodeType.MASTER); return registryClient.getServerList(nodeType);
} }
/**
* query worker list
*
* @param loginUser login user
* @return worker information list
*/
@Override
public List<WorkerServerModel> queryWorker(User loginUser) {
return registryClient.getServerList(RegistryNodeType.WORKER)
.stream()
.map((Server server) -> {
WorkerServerModel model = new WorkerServerModel();
model.setId(server.getId());
model.setHost(server.getHost());
model.setPort(server.getPort());
model.setZkDirectories(Sets.newHashSet(server.getZkDirectory()));
model.setResInfo(server.getResInfo());
model.setCreateTime(server.getCreateTime());
model.setLastHeartbeatTime(server.getLastHeartbeatTime());
return model;
})
.collect(Collectors.toList());
}
@Override
public List<Server> getServerListFromRegistry(boolean isMaster) {
return isMaster
? registryClient.getServerList(RegistryNodeType.MASTER)
: registryClient.getServerList(RegistryNodeType.WORKER);
}
} }

25
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/MonitorControllerTest.java

@ -41,8 +41,7 @@ public class MonitorControllerTest extends AbstractControllerTest {
@Test @Test
public void testListMaster() throws Exception { public void testListMaster() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/MASTER")
MvcResult mvcResult = mockMvc.perform(get("/monitor/masters")
.header(SESSION_ID, sessionId) .header(SESSION_ID, sessionId)
/* .param("type", ResourceType.FILE.name()) */) /* .param("type", ResourceType.FILE.name()) */)
.andExpect(status().isOk()) .andExpect(status().isOk())
@ -59,7 +58,7 @@ public class MonitorControllerTest extends AbstractControllerTest {
@Test @Test
public void testListWorker() throws Exception { public void testListWorker() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/workers") MvcResult mvcResult = mockMvc.perform(get("/monitor/WORKER")
.header(SESSION_ID, sessionId) .header(SESSION_ID, sessionId)
/* .param("type", ResourceType.FILE.name()) */) /* .param("type", ResourceType.FILE.name()) */)
.andExpect(status().isOk()) .andExpect(status().isOk())
@ -74,8 +73,9 @@ public class MonitorControllerTest extends AbstractControllerTest {
} }
@Test @Test
public void testQueryDatabaseState() throws Exception { public void testListAlert() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/databases")
MvcResult mvcResult = mockMvc.perform(get("/monitor/ALERT_SERVER")
.header(SESSION_ID, sessionId) .header(SESSION_ID, sessionId)
/* .param("type", ResourceType.FILE.name()) */) /* .param("type", ResourceType.FILE.name()) */)
.andExpect(status().isOk()) .andExpect(status().isOk())
@ -89,4 +89,19 @@ public class MonitorControllerTest extends AbstractControllerTest {
logger.info(mvcResult.getResponse().getContentAsString()); logger.info(mvcResult.getResponse().getContentAsString());
} }
@Test
public void testQueryDatabaseState() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/monitor/databases")
.header(SESSION_ID, sessionId))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
result.getCode().equals(Status.SUCCESS.getCode());
Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());
logger.info(mvcResult.getResponse().getContentAsString());
}
} }

5
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ExecuteFunctionServiceTest.java

@ -67,6 +67,7 @@ import org.apache.dolphinscheduler.dao.mapper.TaskDefinitionMapper;
import org.apache.dolphinscheduler.dao.mapper.TaskGroupQueueMapper; import org.apache.dolphinscheduler.dao.mapper.TaskGroupQueueMapper;
import org.apache.dolphinscheduler.dao.mapper.TenantMapper; import org.apache.dolphinscheduler.dao.mapper.TenantMapper;
import org.apache.dolphinscheduler.dao.repository.ProcessInstanceDao; import org.apache.dolphinscheduler.dao.repository.ProcessInstanceDao;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import org.apache.dolphinscheduler.service.command.CommandService; import org.apache.dolphinscheduler.service.command.CommandService;
import org.apache.dolphinscheduler.service.process.ProcessService; import org.apache.dolphinscheduler.service.process.ProcessService;
import org.apache.dolphinscheduler.service.process.TriggerRelationService; import org.apache.dolphinscheduler.service.process.TriggerRelationService;
@ -242,7 +243,7 @@ public class ExecuteFunctionServiceTest {
Mockito.when(processService.getTenantForProcess(tenantCode, userId)).thenReturn(tenantCode); Mockito.when(processService.getTenantForProcess(tenantCode, userId)).thenReturn(tenantCode);
doReturn(1).when(commandService).createCommand(argThat(c -> c.getId() == null)); doReturn(1).when(commandService).createCommand(argThat(c -> c.getId() == null));
doReturn(0).when(commandService).createCommand(argThat(c -> c.getId() != null)); doReturn(0).when(commandService).createCommand(argThat(c -> c.getId() != null));
Mockito.when(monitorService.getServerListFromRegistry(true)).thenReturn(getMasterServersList()); Mockito.when(monitorService.listServer(RegistryNodeType.MASTER)).thenReturn(getMasterServersList());
Mockito.when(processService.findProcessInstanceDetailById(processInstanceId)) Mockito.when(processService.findProcessInstanceDetailById(processInstanceId))
.thenReturn(Optional.ofNullable(processInstance)); .thenReturn(Optional.ofNullable(processInstance));
Mockito.when(processService.findProcessDefinition(1L, 1)).thenReturn(this.processDefinition); Mockito.when(processService.findProcessDefinition(1L, 1)).thenReturn(this.processDefinition);
@ -498,7 +499,7 @@ public class ExecuteFunctionServiceTest {
@Test @Test
public void testNoMasterServers() { public void testNoMasterServers() {
Mockito.when(monitorService.getServerListFromRegistry(true)).thenReturn(new ArrayList<>()); Mockito.when(monitorService.listServer(RegistryNodeType.MASTER)).thenReturn(new ArrayList<>());
Assertions.assertThrows(ServiceException.class, () -> executorService.execProcessInstance( Assertions.assertThrows(ServiceException.class, () -> executorService.execProcessInstance(
loginUser, loginUser,

4
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/MonitorServiceTest.java

@ -98,13 +98,13 @@ public class MonitorServiceTest {
public void testQueryMaster() { public void testQueryMaster() {
mockPermissionCheck(ApiFuncIdentificationConstant.MONITOR_MASTER_VIEW, true); mockPermissionCheck(ApiFuncIdentificationConstant.MONITOR_MASTER_VIEW, true);
Mockito.when(registryClient.getServerList(RegistryNodeType.MASTER)).thenReturn(getServerList()); Mockito.when(registryClient.getServerList(RegistryNodeType.MASTER)).thenReturn(getServerList());
assertDoesNotThrow(() -> monitorService.queryMaster(user)); assertDoesNotThrow(() -> monitorService.listServer(RegistryNodeType.MASTER));
} }
@Test @Test
public void testQueryWorker() { public void testQueryWorker() {
Mockito.when(registryClient.getServerList(RegistryNodeType.WORKER)).thenReturn(getServerList()); Mockito.when(registryClient.getServerList(RegistryNodeType.WORKER)).thenReturn(getServerList());
AssertionsHelper.assertDoesNotThrow(() -> monitorService.queryWorker(user)); AssertionsHelper.assertDoesNotThrow(() -> monitorService.listServer(RegistryNodeType.WORKER));
} }
@Test @Test

7
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/CommandMapper.java

@ -26,6 +26,8 @@ import java.util.Date;
import java.util.List; import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/** /**
* command mapper interface * command mapper interface
@ -50,7 +52,7 @@ public interface CommandMapper extends BaseMapper<Command> {
* *
* @return * @return
*/ */
List<Command> queryCommandPage(@Param("limit") int limit, @Param("offset") int offset); IPage<Command> queryCommandPage(Page<Command> page);
List<Command> queryCommandByIdSlot(@Param("currentSlotIndex") int currentSlotIndex, List<Command> queryCommandByIdSlot(@Param("currentSlotIndex") int currentSlotIndex,
@Param("totalSlot") int totalSlot, @Param("totalSlot") int totalSlot,
@ -58,4 +60,7 @@ public interface CommandMapper extends BaseMapper<Command> {
@Param("fetchNumber") int fetchNum); @Param("fetchNumber") int fetchNum);
void deleteByWorkflowInstanceIds(@Param("workflowInstanceIds") List<Integer> workflowInstanceIds); void deleteByWorkflowInstanceIds(@Param("workflowInstanceIds") List<Integer> workflowInstanceIds);
IPage<Command> queryCommandPageByIds(Page<Command> page,
@Param("workflowDefinitionCodes") List<Long> workflowDefinitionCodes);
} }

7
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.java

@ -26,6 +26,8 @@ import java.util.Date;
import java.util.List; import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/** /**
* error command mapper interface * error command mapper interface
@ -43,4 +45,9 @@ public interface ErrorCommandMapper extends BaseMapper<ErrorCommand> {
@Param("startTime") Date startTime, @Param("startTime") Date startTime,
@Param("endTime") Date endTime, @Param("endTime") Date endTime,
@Param("projectCodes") List<Long> projectCodes); @Param("projectCodes") List<Long> projectCodes);
IPage<ErrorCommand> queryErrorCommandPage(Page<ErrorCommand> page);
IPage<ErrorCommand> queryErrorCommandPageByIds(Page<ErrorCommand> page,
@Param("workflowDefinitionCodes") List<Long> workflowDefinitionCodes);
} }

1
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProcessDefinitionMapper.java

@ -188,4 +188,5 @@ public interface ProcessDefinitionMapper extends BaseMapper<ProcessDefinition> {
* @return project ids list * @return project ids list
*/ */
List<Integer> listProjectIds(); List<Integer> listProjectIds();
List<Long> queryDefinitionCodeListByProjectCodes(@Param("projectCodes") List<Long> projectCodes);
} }

16
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/CommandMapper.xml

@ -34,10 +34,22 @@
group by cmd.command_type group by cmd.command_type
</select> </select>
<select id="queryCommandPage" resultType="org.apache.dolphinscheduler.dao.entity.Command"> <select id="queryCommandPage" resultType="org.apache.dolphinscheduler.dao.entity.Command">
select * select
*
from t_ds_command
where 1 = 1
order by process_instance_priority, id asc
</select>
<select id="queryCommandPageByIds" resultType="org.apache.dolphinscheduler.dao.entity.Command">
select
*
from t_ds_command from t_ds_command
where process_definition_code in
<foreach item="id" index="index" collection="workflowDefinitionCodes" open="(" separator="," close=")">
#{id}
</foreach>
order by process_instance_priority, id asc order by process_instance_priority, id asc
limit #{limit} offset #{offset}
</select> </select>
<select id="queryCommandByIdSlot" resultType="org.apache.dolphinscheduler.dao.entity.Command"> <select id="queryCommandByIdSlot" resultType="org.apache.dolphinscheduler.dao.entity.Command">

19
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ErrorCommandMapper.xml

@ -33,4 +33,23 @@
</if> </if>
group by cmd.command_type group by cmd.command_type
</select> </select>
<select id="queryErrorCommandPage" resultType="org.apache.dolphinscheduler.dao.entity.ErrorCommand">
select
*
from t_ds_error_command
order by process_instance_priority, id asc
</select>
<select id="queryErrorCommandPageByIds" resultType="org.apache.dolphinscheduler.dao.entity.ErrorCommand">
select
*
from t_ds_error_command
where process_definition_code in
<foreach item="id" index="index" collection="workflowDefinitionCodes" open="(" separator="," close=")">
#{id}
</foreach>
order by process_instance_priority, id asc
</select>
</mapper> </mapper>

10
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ProcessDefinitionMapper.xml

@ -208,4 +208,14 @@
SELECT DISTINCT(id) as project_id SELECT DISTINCT(id) as project_id
FROM t_ds_project FROM t_ds_project
</select> </select>
<select id="queryDefinitionCodeListByProjectCodes" resultType="java.lang.Long">
select
code
from t_ds_process_definition
where project_code in
<foreach collection="projectCodes" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</select>
</mapper> </mapper>

3
dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/CommandMapperTest.java

@ -42,6 +42,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
/** /**
@ -135,7 +136,7 @@ public class CommandMapperTest extends BaseDaoTest {
createCommand(CommandType.START_PROCESS, processDefinition.getCode()); createCommand(CommandType.START_PROCESS, processDefinition.getCode());
List<Command> actualCommand = commandMapper.queryCommandPage(1, 0); List<Command> actualCommand = commandMapper.selectList(new QueryWrapper<>());
Assertions.assertNotNull(actualCommand); Assertions.assertNotNull(actualCommand);
} }

1
dolphinscheduler-registry/dolphinscheduler-registry-api/src/main/java/org/apache/dolphinscheduler/registry/api/enums/RegistryNodeType.java

@ -37,5 +37,4 @@ public enum RegistryNodeType {
private final String name; private final String name;
private final String registryPath; private final String registryPath;
} }

4
dolphinscheduler-ui/src/layouts/content/use-dataList.ts

@ -255,6 +255,10 @@ export function useDataList() {
label: t('menu.worker'), label: t('menu.worker'),
key: '/monitor/worker' key: '/monitor/worker'
}, },
{
label: t('menu.alert_server'),
key: '/monitor/alert_server'
},
{ {
label: t('menu.db'), label: t('menu.db'),
key: '/monitor/db' key: '/monitor/db'

1
dolphinscheduler-ui/src/locales/en_US/menu.ts

@ -40,6 +40,7 @@ export default {
service_manage: 'Service Manage', service_manage: 'Service Manage',
master: 'Master', master: 'Master',
worker: 'Worker', worker: 'Worker',
alert_server: 'Alert Server',
db: 'DB', db: 'DB',
statistical_manage: 'Statistical Manage', statistical_manage: 'Statistical Manage',
statistics: 'Statistics', statistics: 'Statistics',

6
dolphinscheduler-ui/src/locales/en_US/monitor.ts

@ -35,6 +35,7 @@ export default {
memory_usage: 'Memory Usage', memory_usage: 'Memory Usage',
disk_available: 'Disk Available', disk_available: 'Disk Available',
load_average: 'Load Average', load_average: 'Load Average',
thread_pool_usage: 'Thread Pool Usage',
create_time: 'Create Time', create_time: 'Create Time',
last_heartbeat_time: 'Last Heartbeat Time', last_heartbeat_time: 'Last Heartbeat Time',
directory_detail: 'Directory Detail', directory_detail: 'Directory Detail',
@ -44,6 +45,11 @@ export default {
worker_no_data_result_desc: worker_no_data_result_desc:
'Currently, there are no worker nodes exist, please create a worker node and refresh this page' 'Currently, there are no worker nodes exist, please create a worker node and refresh this page'
}, },
alert_server: {
alert_server_no_data_result_title: 'No Alert Server Nodes Exist',
alert_server_no_data_result_desc:
'Currently, there are no alert server nodes exist, please create a alert server node and refresh this page'
},
db: { db: {
health_state: 'Health State', health_state: 'Health State',
max_connections: 'Max Connections', max_connections: 'Max Connections',

1
dolphinscheduler-ui/src/locales/zh_CN/menu.ts

@ -41,6 +41,7 @@ export default {
service_manage: '服务管理', service_manage: '服务管理',
master: 'Master', master: 'Master',
worker: 'Worker', worker: 'Worker',
alert_server: 'Alert Server',
db: 'DB', db: 'DB',
statistical_manage: '统计管理', statistical_manage: '统计管理',
statistics: 'Statistics', statistics: 'Statistics',

6
dolphinscheduler-ui/src/locales/zh_CN/monitor.ts

@ -35,6 +35,7 @@ export default {
memory_usage: '内存使用量', memory_usage: '内存使用量',
disk_available: '磁盘可用容量', disk_available: '磁盘可用容量',
load_average: '平均负载量', load_average: '平均负载量',
thread_pool_usage: '线程池使用量',
create_time: '创建时间', create_time: '创建时间',
last_heartbeat_time: '最后心跳时间', last_heartbeat_time: '最后心跳时间',
directory_detail: '目录详情', directory_detail: '目录详情',
@ -44,6 +45,11 @@ export default {
worker_no_data_result_desc: worker_no_data_result_desc:
'目前没有任何Worker节点,请先创建Worker节点,再访问该页面' '目前没有任何Worker节点,请先创建Worker节点,再访问该页面'
}, },
alert_server: {
alert_server_no_data_result_title: 'Alert Server节点不存在',
alert_server_no_data_result_desc:
'目前没有任何Alert Server节点,请先创建Alert Server节点,再访问该页面'
},
db: { db: {
health_state: '健康状态', health_state: '健康状态',
max_connections: '最大连接数', max_connections: '最大连接数',

11
dolphinscheduler-ui/src/router/modules/monitor.ts

@ -51,6 +51,17 @@ export default {
auth: [] auth: []
} }
}, },
{
path: '/monitor/alert_server',
name: 'servers-alert-server',
component: components['monitor-servers-alert_server'],
meta: {
title: '服务管理-Alert Server',
activeMenu: 'monitor',
showSide: true,
auth: []
}
},
{ {
path: '/monitor/db', path: '/monitor/db',
name: 'servers-db', name: 'servers-db',

8
dolphinscheduler-ui/src/service/modules/monitor/index.ts

@ -16,6 +16,7 @@
*/ */
import { axios } from '@/service/service' import { axios } from '@/service/service'
import type { ServerNodeType } from './types'
export function queryDatabaseState(): any { export function queryDatabaseState(): any {
return axios({ return axios({
@ -37,3 +38,10 @@ export function listWorker(): any {
method: 'get' method: 'get'
}) })
} }
export function listMonitorServerNode(nodeType: ServerNodeType): any {
return axios({
url: `/monitor/${nodeType}`,
method: 'get'
})
}

31
dolphinscheduler-ui/src/service/modules/monitor/types.ts

@ -25,7 +25,9 @@ interface DatabaseRes {
date: string date: string
} }
interface MasterNode { type ServerNodeType = 'MASTER' | 'WORKER' | 'ALERT_SERVER'
interface ServerNode {
id: number id: number
host: string host: string
port: number port: number
@ -35,14 +37,23 @@ interface MasterNode {
lastHeartbeatTime: string lastHeartbeatTime: string
} }
interface WorkerNode { interface MasterNode extends ServerNode {
id: number serverStatus?: 'NORMAL' | 'BUZY'
host: string }
port: number
zkDirectories: Array<string> interface WorkerNode extends ServerNode {
resInfo: string serverStatus?: 'NORMAL' | 'BUZY'
createTime: string workerHostWeight?: number
lastHeartbeatTime: string threadPoolUsage?: number
} }
export { DatabaseRes, MasterNode, WorkerNode } interface AlertNode extends MasterNode {}
export {
DatabaseRes,
MasterNode,
WorkerNode,
ServerNodeType,
ServerNode,
AlertNode
}

18
dolphinscheduler-ui/src/service/modules/projects-analysis/index.ts

@ -16,7 +16,7 @@
*/ */
import { axios } from '@/service/service' import { axios } from '@/service/service'
import { CodeReq, StateReq } from './types' import { ListReq, CodeReq, StateReq } from './types'
export function countCommandState(): any { export function countCommandState(): any {
return axios({ return axios({
@ -55,3 +55,19 @@ export function countTaskState(params: StateReq): any {
params params
}) })
} }
export function queryListCommandPaging(params: ListReq): any {
return axios({
url: '/projects/analysis/listCommand',
method: 'get',
params
})
}
export function queryListErrorCommandPaging(params: ListReq): any {
return axios({
url: '/projects/analysis/listErrorCommand',
method: 'get',
params
})
}

9
dolphinscheduler-ui/src/service/modules/projects-analysis/types.ts

@ -66,6 +66,12 @@ interface CommandStateRes {
commandState: string commandState: string
} }
interface ListReq {
pageNo: number
pageSize: number
searchVal?: string
}
export { export {
CodeReq, CodeReq,
StateReq, StateReq,
@ -73,5 +79,6 @@ export {
WorkflowInstanceCountVo, WorkflowInstanceCountVo,
TaskInstanceCountVo, TaskInstanceCountVo,
TaskQueueRes, TaskQueueRes,
CommandStateRes CommandStateRes,
ListReq
} }

43
dolphinscheduler-ui/src/views/monitor/servers/alert_server/index.module.scss

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@mixin base {
font-size: 5vw;
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
}
.card {
@include base;
}
.load-average {
@include base;
color: var(--n-color-target);
}
.link-btn {
color: var(--n-color-target);
cursor: pointer;
&:hover {
color: var(--n-color-target);
opacity: 0.8;
}
}

189
dolphinscheduler-ui/src/views/monitor/servers/alert_server/index.tsx

@ -0,0 +1,189 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineComponent, onMounted, ref, toRefs } from 'vue'
import { NGrid, NGi, NCard, NNumberAnimation, NSpace, NTag } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useServerNode } from './use-server-node'
import styles from './index.module.scss'
import Card from '@/components/card'
import Result from '@/components/result'
import Gauge from '@/components/chart/modules/Gauge'
import NodeModal from './node-modal'
import type { Ref } from 'vue'
import type { RowData } from 'naive-ui/es/data-table/src/interface'
import type { AlertNode } from '@/service/modules/monitor/types'
import { capitalize } from 'lodash'
const alertServer = defineComponent({
name: 'alertServer',
setup() {
const showModalRef = ref(false)
const { t } = useI18n()
const { variables, getTableData } = useServerNode()
const zkDirectoryRef: Ref<Array<RowData>> = ref([])
const clickDetails = (zkDirectories: string) => {
zkDirectoryRef.value = [{ directory: zkDirectories, index: 1 }]
showModalRef.value = true
}
const onConfirmModal = () => {
showModalRef.value = false
}
onMounted(() => {
getTableData()
})
return {
t,
...toRefs(variables),
clickDetails,
onConfirmModal,
showModalRef,
zkDirectoryRef
}
},
render() {
const { t, clickDetails, onConfirmModal, showModalRef, zkDirectoryRef } =
this
const renderNodeServerStatusTag = (item: AlertNode) => {
const serverStatus = JSON.parse(item.resInfo)?.serverStatus
if (!serverStatus) return ''
return (
<NTag type={serverStatus === 'NORMAL' ? 'info' : 'warning'}>
{capitalize(serverStatus)}
</NTag>
)
}
return this.data.length < 1 ? (
<Result
title={t('monitor.alert_server.alert_server_no_data_result_title')}
description={t('monitor.alert_server.alert_server_no_data_result_desc')}
status={'info'}
size={'medium'}
/>
) : (
<>
<NSpace vertical size={25}>
{this.data.map((item: AlertNode) => {
return (
<NSpace vertical>
<NCard>
<NSpace
justify='space-between'
style={{
'line-height': '28px'
}}
>
<NSpace>
{renderNodeServerStatusTag(item)}
<span>{`${t('monitor.master.host')}: ${
item ? item.host : ' - '
}`}</span>
<span
class={styles['link-btn']}
onClick={() => clickDetails(item.zkDirectory)}
>
{t('monitor.master.directory_detail')}
</span>
</NSpace>
<NSpace>
<span>{`${t('monitor.master.create_time')}: ${
item ? item.createTime : ' - '
}`}</span>
<span>{`${t('monitor.master.last_heartbeat_time')}: ${
item ? item.lastHeartbeatTime : ' - '
}`}</span>
</NSpace>
</NSpace>
</NCard>
<NGrid x-gap='12' cols='4'>
<NGi>
<Card title={t('monitor.master.cpu_usage')}>
<div class={styles.card}>
{item && (
<Gauge
data={(
JSON.parse(item.resInfo).cpuUsage * 100
).toFixed(2)}
/>
)}
</div>
</Card>
</NGi>
<NGi>
<Card title={t('monitor.master.memory_usage')}>
<div class={styles.card}>
{item && (
<Gauge
data={(
JSON.parse(item.resInfo).memoryUsage * 100
).toFixed(2)}
/>
)}
</div>
</Card>
</NGi>
<NGi>
<Card title={t('monitor.master.disk_available')}>
<div class={[styles.card, styles['load-average']]}>
{item && (
<NNumberAnimation
precision={2}
from={0}
to={JSON.parse(item.resInfo).diskAvailable}
/>
)}
</div>
</Card>
</NGi>
<NGi>
<Card title={t('monitor.master.load_average')}>
<div class={[styles.card, styles['load-average']]}>
{item && (
<NNumberAnimation
precision={2}
from={0}
to={JSON.parse(item.resInfo).loadAverage}
/>
)}
</div>
</Card>
</NGi>
</NGrid>
</NSpace>
)
})}
</NSpace>
<NodeModal
showModal={showModalRef}
data={zkDirectoryRef}
onConfirmModal={onConfirmModal}
></NodeModal>
</>
)
}
})
export default alertServer

80
dolphinscheduler-ui/src/views/monitor/servers/alert_server/node-modal.tsx

@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'
import { NDataTable } from 'naive-ui'
import Modal from '@/components/modal'
import type { PropType } from 'vue'
import type {
RowData,
TableColumns
} from 'naive-ui/es/data-table/src/interface'
const props = {
showModal: {
type: Boolean as PropType<boolean>,
default: false
},
data: {
type: Array as PropType<Array<RowData>>,
default: () => []
}
}
const NodeModal = defineComponent({
props,
emits: ['confirmModal'],
setup(props, ctx) {
const { t } = useI18n()
const columnsRef: TableColumns<any> = [
{ title: '#', key: 'index', render: (row, index) => index + 1 },
{ title: t('monitor.master.directory'), key: 'directory' }
]
const onConfirm = () => {
ctx.emit('confirmModal')
}
return { t, columnsRef, onConfirm }
},
render() {
const { t, columnsRef, onConfirm } = this
return (
<Modal
title={t('monitor.master.directory_detail')}
show={this.showModal}
cancelShow={false}
onConfirm={onConfirm}
>
{{
default: () => (
<NDataTable
columns={columnsRef}
data={this.data}
striped
size={'small'}
/>
)
}}
</Modal>
)
}
})
export default NodeModal

38
dolphinscheduler-ui/src/views/monitor/servers/alert_server/use-server-node.ts

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { reactive } from 'vue'
import { useAsyncState } from '@vueuse/core'
import { listMonitorServerNode } from '@/service/modules/monitor'
import type { AlertNode } from '@/service/modules/monitor/types'
export function useServerNode() {
const variables = reactive({
data: []
})
const getTableData = () => {
const { state } = useAsyncState(
listMonitorServerNode('ALERT_SERVER').then((res: Array<AlertNode>) => {
variables.data = res as any
}),
[]
)
return state
}
return { variables, getTableData }
}

24
dolphinscheduler-ui/src/views/monitor/servers/master/index.tsx

@ -16,7 +16,7 @@
*/ */
import { defineComponent, onMounted, ref, toRefs } from 'vue' import { defineComponent, onMounted, ref, toRefs } from 'vue'
import { NGrid, NGi, NCard, NNumberAnimation, NSpace } from 'naive-ui' import { NGrid, NGi, NCard, NNumberAnimation, NSpace, NTag } from 'naive-ui'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useMaster } from './use-master' import { useMaster } from './use-master'
import styles from './index.module.scss' import styles from './index.module.scss'
@ -27,6 +27,7 @@ import MasterModal from './master-modal'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { RowData } from 'naive-ui/es/data-table/src/interface' import type { RowData } from 'naive-ui/es/data-table/src/interface'
import type { MasterNode } from '@/service/modules/monitor/types' import type { MasterNode } from '@/service/modules/monitor/types'
import { capitalize } from 'lodash'
const master = defineComponent({ const master = defineComponent({
name: 'master', name: 'master',
@ -62,6 +63,18 @@ const master = defineComponent({
const { t, clickDetails, onConfirmModal, showModalRef, zkDirectoryRef } = const { t, clickDetails, onConfirmModal, showModalRef, zkDirectoryRef } =
this this
const renderNodeServerStatusTag = (item: MasterNode) => {
const serverStatus = JSON.parse(item.resInfo)?.serverStatus
if (!serverStatus) return ''
return (
<NTag type={serverStatus === 'NORMAL' ? 'info' : 'warning'}>
{capitalize(serverStatus)}
</NTag>
)
}
return this.data.length < 1 ? ( return this.data.length < 1 ? (
<Result <Result
title={t('monitor.master.master_no_data_result_title')} title={t('monitor.master.master_no_data_result_title')}
@ -76,8 +89,15 @@ const master = defineComponent({
return ( return (
<NSpace vertical> <NSpace vertical>
<NCard> <NCard>
<NSpace justify='space-between'> <NSpace
justify='space-between'
style={{
'line-height': '28px'
}}
>
<NSpace> <NSpace>
{renderNodeServerStatusTag(item)}
<span>{`${t('monitor.master.host')}: ${ <span>{`${t('monitor.master.host')}: ${
item ? item.host : ' - ' item ? item.host : ' - '
}`}</span> }`}</span>

4
dolphinscheduler-ui/src/views/monitor/servers/master/use-master.ts

@ -17,7 +17,7 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { useAsyncState } from '@vueuse/core' import { useAsyncState } from '@vueuse/core'
import { listMaster } from '@/service/modules/monitor' import { listMonitorServerNode } from '@/service/modules/monitor'
import type { MasterNode } from '@/service/modules/monitor/types' import type { MasterNode } from '@/service/modules/monitor/types'
export function useMaster() { export function useMaster() {
@ -26,7 +26,7 @@ export function useMaster() {
}) })
const getTableMaster = () => { const getTableMaster = () => {
const { state } = useAsyncState( const { state } = useAsyncState(
listMaster().then((res: Array<MasterNode>) => { listMonitorServerNode('MASTER').then((res: Array<MasterNode>) => {
variables.data = res as any variables.data = res as any
}), }),
[] []

63
dolphinscheduler-ui/src/views/monitor/servers/worker/index.tsx

@ -16,7 +16,7 @@
*/ */
import { defineComponent, onMounted, ref, toRefs } from 'vue' import { defineComponent, onMounted, ref, toRefs } from 'vue'
import { NGrid, NGi, NCard, NNumberAnimation, NSpace } from 'naive-ui' import { NGrid, NGi, NCard, NNumberAnimation, NSpace, NTag } from 'naive-ui'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useWorker } from './use-worker' import { useWorker } from './use-worker'
import styles from './index.module.scss' import styles from './index.module.scss'
@ -27,6 +27,7 @@ import WorkerModal from './worker-modal'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { RowData } from 'naive-ui/es/data-table/src/interface' import type { RowData } from 'naive-ui/es/data-table/src/interface'
import type { WorkerNode } from '@/service/modules/monitor/types' import type { WorkerNode } from '@/service/modules/monitor/types'
import { capitalize } from 'lodash'
const worker = defineComponent({ const worker = defineComponent({
name: 'worker', name: 'worker',
@ -36,12 +37,8 @@ const worker = defineComponent({
const { variables, getTableWorker } = useWorker() const { variables, getTableWorker } = useWorker()
const zkDirectoryRef: Ref<Array<RowData>> = ref([]) const zkDirectoryRef: Ref<Array<RowData>> = ref([])
const clickDetails = (zkDirectories: Array<string>) => { const clickDetails = (zkDirectories: string) => {
zkDirectoryRef.value = zkDirectories.map((zkItem) => { zkDirectoryRef.value = [{ directory: zkDirectories, index: 1 }]
return {
directory: zkItem
}
})
showModalRef.value = true showModalRef.value = true
} }
@ -66,6 +63,18 @@ const worker = defineComponent({
const { t, clickDetails, onConfirmModal, showModalRef, zkDirectoryRef } = const { t, clickDetails, onConfirmModal, showModalRef, zkDirectoryRef } =
this this
const renderNodeServerStatusTag = (item: WorkerNode) => {
const serverStatus = JSON.parse(item.resInfo)?.serverStatus
if (!serverStatus) return ''
return (
<NTag type={serverStatus === 'NORMAL' ? 'info' : 'warning'}>
{capitalize(serverStatus)}
</NTag>
)
}
return this.data.length < 1 ? ( return this.data.length < 1 ? (
<Result <Result
title={t('monitor.worker.worker_no_data_result_title')} title={t('monitor.worker.worker_no_data_result_title')}
@ -80,14 +89,21 @@ const worker = defineComponent({
return ( return (
<NSpace vertical> <NSpace vertical>
<NCard> <NCard>
<NSpace justify='space-between'> <NSpace
justify='space-between'
style={{
'line-height': '28px'
}}
>
<NSpace> <NSpace>
{renderNodeServerStatusTag(item)}
<span>{`${t('monitor.worker.host')}: ${ <span>{`${t('monitor.worker.host')}: ${
item ? item.host : ' - ' item ? item.host : ' - '
}`}</span> }`}</span>
<span <span
class={styles['link-btn']} class={styles['link-btn']}
onClick={() => clickDetails(item.zkDirectories)} onClick={() => clickDetails(item.zkDirectory)}
> >
{t('monitor.worker.directory_detail')} {t('monitor.worker.directory_detail')}
</span> </span>
@ -102,7 +118,7 @@ const worker = defineComponent({
</NSpace> </NSpace>
</NSpace> </NSpace>
</NCard> </NCard>
<NGrid x-gap='12' cols='4'> <NGrid x-gap='12' cols='5'>
<NGi> <NGi>
<Card title={t('monitor.worker.cpu_usage')}> <Card title={t('monitor.worker.cpu_usage')}>
<div class={styles.card}> <div class={styles.card}>
@ -155,6 +171,33 @@ const worker = defineComponent({
</div> </div>
</Card> </Card>
</NGi> </NGi>
<NGi>
<Card title={t('monitor.worker.thread_pool_usage')}>
<div
class={[styles.card, styles['load-average']]}
style={{
'font-size': '90px'
}}
>
{item && (
<>
<NNumberAnimation
precision={0}
from={0}
to={JSON.parse(item.resInfo).threadPoolUsage}
/>
/
<NNumberAnimation
precision={0}
from={0}
to={JSON.parse(item.resInfo).workerHostWeight}
/>
</>
)}
</div>
</Card>
</NGi>
</NGrid> </NGrid>
</NSpace> </NSpace>
) )

4
dolphinscheduler-ui/src/views/monitor/servers/worker/use-worker.ts

@ -17,7 +17,7 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { useAsyncState } from '@vueuse/core' import { useAsyncState } from '@vueuse/core'
import { listWorker } from '@/service/modules/monitor' import { listMonitorServerNode } from '@/service/modules/monitor'
import type { WorkerNode } from '@/service/modules/monitor/types' import type { WorkerNode } from '@/service/modules/monitor/types'
export function useWorker() { export function useWorker() {
@ -27,7 +27,7 @@ export function useWorker() {
const getTableWorker = () => { const getTableWorker = () => {
const { state } = useAsyncState( const { state } = useAsyncState(
listWorker().then((res: Array<WorkerNode>) => { listMonitorServerNode('WORKER').then((res: Array<WorkerNode>) => {
variables.data = res as any variables.data = res as any
}), }),
[] []

74
dolphinscheduler-ui/src/views/monitor/statistics/statistics/index.tsx

@ -15,58 +15,44 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineComponent, ref } from 'vue' import { defineComponent } from 'vue'
import { NGrid, NGi, NNumberAnimation } from 'naive-ui' import { NGrid, NGi, NTabs, NTabPane, NCard } from 'naive-ui'
import { useStatistics } from './use-statistics' import ListCommandTable from './list-command-table'
import { useI18n } from 'vue-i18n' import ListErrorCommandTable from './list-error-command-table'
import Card from '@/components/card'
import styles from './index.module.scss'
const statistics = defineComponent({ const statistics = defineComponent({
name: 'statistics', name: 'statistics',
setup() { setup() {},
const { t } = useI18n()
const { getStatistics } = useStatistics()
const statisticsRef = ref(getStatistics())
return { t, statisticsRef }
},
render() { render() {
const { t, statisticsRef } = this
return ( return (
<NGrid x-gap='12' y-gap='8' cols='2' responsive='screen'> <NGrid x-gap='12' y-gap='8' cols='1' responsive='screen'>
<NGi> <NGi>
<Card <NCard>
title={t( <NTabs
'monitor.statistics.command_number_of_waiting_for_running' type='card'
)} animated
pane-style={{
padding: '0px',
border: 'none'
}}
> >
<div class={styles.connections}> <NTabPane
{statisticsRef.command.length > 0 && ( name='command'
<NNumberAnimation tab='Command Statistics List'
from={0} display-directiv='show'
to={statisticsRef.command >
.map((item) => item.normalCount) <ListCommandTable></ListCommandTable>
.reduce((prev, next) => prev + next)} </NTabPane>
/> <NTabPane
)} name='command-error'
</div> tab='Failure Command Statistics List'
</Card> display-directiv='show'
</NGi> >
<NGi> <ListErrorCommandTable></ListErrorCommandTable>
<Card title={t('monitor.statistics.failure_command_number')}> </NTabPane>
<div class={styles.connections}> </NTabs>
{statisticsRef.command.length > 0 && ( </NCard>
<NNumberAnimation
from={0}
to={statisticsRef.command
.map((item) => item.errorCount)
.reduce((prev, next) => prev + next)}
/>
)}
</div>
</Card>
</NGi> </NGi>
</NGrid> </NGrid>
) )

233
dolphinscheduler-ui/src/views/monitor/statistics/statistics/list-command-table.tsx

@ -0,0 +1,233 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
defineComponent,
onMounted,
toRefs,
watch,
reactive,
ref,
h
} from 'vue'
import { NSpace, NDataTable, NPagination } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import Card from '@/components/card'
import {
COLUMN_WIDTH_CONFIG,
calculateTableWidth,
DefaultTableWidth
} from '@/common/column-width-config'
import { useAsyncState } from '@vueuse/core'
import { queryListCommandPaging } from '@/service/modules/projects-analysis'
const ListCommandTable = defineComponent({
name: 'list-command-table',
setup() {
const { t } = useI18n()
const variables = reactive({
columns: [],
tableWidth: DefaultTableWidth,
tableData: [],
page: ref(1),
pageSize: ref(10),
userName: ref(null),
totalPage: ref(1),
loadingRef: ref(false)
})
const createColumns = (variables: any) => {
variables.columns = [
{
title: 'ID',
key: 'id',
...COLUMN_WIDTH_CONFIG['index']
},
{
title: 'Command Type',
key: 'commandType',
...COLUMN_WIDTH_CONFIG['userName']
},
{
title: 'Command Param',
key: 'commandParam',
...COLUMN_WIDTH_CONFIG['linkName']
},
{
title: 'Task Info',
key: 'id',
width: 300,
render: (row: any) => {
return h('div', [
`Definition Code:${row.processDefinitionCode} `,
h('br'),
`Definition Version:${row.processDefinitionVersion} `,
h('br'),
`Instance Id:${row.processInstanceId} `,
h('br'),
`Instance Priority:${row.processInstancePriority} `
])
}
},
{
title: 'Task Params',
key: 'id',
width: 300,
render: (row: any) => {
return h('div', [
`DryRun:${row.dryRun} `,
h('br'),
`Environment Code:${row.environmentCode} `,
h('br'),
`Failure Strategy:${row.failureStrategy} `,
h('br'),
`Task Depend Type:${row.taskDependType} `
])
}
},
{
title: 'Worker Info',
key: 'id',
width: 220,
render: (row: any) => {
return h('div', [
`Worker Group:${row.workerGroup} `,
h('br'),
`Tenant Code:${row.tenantCode} `,
h('br'),
`Test Flag:${row.testFlag} `
])
}
},
{
title: 'Warning Info',
key: 'id',
width: 200,
render: (row: any) => {
return h('div', [
`Warning Group Id:${row.warningGroupId} `,
h('br'),
`Warning Type:${row.warningType} `
])
}
},
{
title: 'Executor Id',
key: 'executorId',
...COLUMN_WIDTH_CONFIG['type']
},
{
title: 'Time',
key: 'startTime',
width: 280,
render: (row: any) => {
return h('div', [
`Start Time:${row.startTime} `,
h('br'),
`Update Time:${row.updateTime} `,
h('br'),
`Schedule Time:${row.scheduleTime} `
])
}
}
]
if (variables.tableWidth) {
variables.tableWidth = calculateTableWidth(variables.columns)
}
}
const getTableData = () => {
if (variables.loadingRef) return
variables.loadingRef = true
const data = {
pageSize: variables.pageSize,
pageNo: variables.page
}
const { state } = useAsyncState(
queryListCommandPaging(data).then((res: any) => {
variables.totalPage = res.totalPage
variables.tableData = res.totalList
variables.loadingRef = false
}),
{}
)
return state
}
const onUpdatePageSize = () => {
variables.page = 1
getTableData()
}
onMounted(() => {
createColumns(variables)
getTableData()
})
watch(useI18n().locale, () => {
createColumns(variables)
})
return {
t,
...toRefs(variables),
getTableData,
onUpdatePageSize
}
},
render() {
const { getTableData, onUpdatePageSize, loadingRef } = this
return (
<NSpace vertical>
<Card>
<NSpace vertical>
<NDataTable
size={'small'}
loading={loadingRef}
columns={this.columns}
scrollX={this.tableWidth}
data={this.tableData}
/>
<NSpace justify='center'>
<NPagination
v-model:page={this.page}
v-model:page-size={this.pageSize}
page-count={this.totalPage}
show-size-picker
page-sizes={[10, 30, 50]}
show-quick-jumper
onUpdatePage={getTableData}
onUpdatePageSize={onUpdatePageSize}
/>
</NSpace>
</NSpace>
</Card>
</NSpace>
)
}
})
export default ListCommandTable

237
dolphinscheduler-ui/src/views/monitor/statistics/statistics/list-error-command-table.tsx

@ -0,0 +1,237 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
defineComponent,
onMounted,
toRefs,
watch,
reactive,
ref,
h
} from 'vue'
import { NSpace, NDataTable, NPagination } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import Card from '@/components/card'
import {
COLUMN_WIDTH_CONFIG,
calculateTableWidth,
DefaultTableWidth
} from '@/common/column-width-config'
import { useAsyncState } from '@vueuse/core'
import { queryListErrorCommandPaging } from '@/service/modules/projects-analysis'
const ListErrorCommandTable = defineComponent({
name: 'list-error-command-table',
setup() {
const { t } = useI18n()
const variables = reactive({
columns: [],
tableWidth: DefaultTableWidth,
tableData: [],
page: ref(1),
pageSize: ref(10),
userName: ref(null),
totalPage: ref(1),
loadingRef: ref(false)
})
const createColumns = (variables: any) => {
variables.columns = [
{
title: 'ID',
key: 'id',
...COLUMN_WIDTH_CONFIG['index']
},
{
title: 'Command Type',
key: 'commandType',
...COLUMN_WIDTH_CONFIG['userName']
},
{
title: 'Command Param',
key: 'commandParam',
...COLUMN_WIDTH_CONFIG['linkName']
},
{
title: 'Task Info',
key: 'id',
width: 300,
render: (row: any) => {
return h('div', [
`Definition Code:${row.processDefinitionCode} `,
h('br'),
`Definition Version:${row.processDefinitionVersion} `,
h('br'),
`Instance Id:${row.processInstanceId} `,
h('br'),
`Instance Priority:${row.processInstancePriority} `
])
}
},
{
title: 'Task Params',
key: 'id',
width: 300,
render: (row: any) => {
return h('div', [
`DryRun:${row.dryRun} `,
h('br'),
`Environment Code:${row.environmentCode} `,
h('br'),
`Failure Strategy:${row.failureStrategy} `,
h('br'),
`Task Depend Type:${row.taskDependType} `
])
}
},
{
title: 'Worker Info',
key: 'id',
width: 220,
render: (row: any) => {
return h('div', [
`Worker Group:${row.workerGroup} `,
h('br'),
`Tenant Code:${row.tenantCode} `,
h('br'),
`Test Flag:${row.testFlag} `
])
}
},
{
title: 'Warning Info',
key: 'id',
width: 200,
render: (row: any) => {
return h('div', [
`Warning Group Id:${row.warningGroupId} `,
h('br'),
`Warning Type:${row.warningType} `
])
}
},
{
title: 'Message',
key: 'message',
...COLUMN_WIDTH_CONFIG['linkName']
},
{
title: 'Executor Id',
key: 'executorId',
...COLUMN_WIDTH_CONFIG['type']
},
{
title: 'Time',
key: 'startTime',
width: 280,
render: (row: any) => {
return h('div', [
`Start Time:${row.startTime || '-'} `,
h('br'),
`Update Time:${row.updateTime || '-'} `,
h('br'),
`Schedule Time:${row.scheduleTime || '-'} `
])
}
}
]
if (variables.tableWidth) {
variables.tableWidth = calculateTableWidth(variables.columns)
}
}
const getTableData = () => {
if (variables.loadingRef) return
variables.loadingRef = true
const data = {
pageSize: variables.pageSize,
pageNo: variables.page
}
const { state } = useAsyncState(
queryListErrorCommandPaging(data).then((res: any) => {
variables.totalPage = res.totalPage
variables.tableData = res.totalList
variables.loadingRef = false
}),
{}
)
return state
}
const onUpdatePageSize = () => {
variables.page = 1
getTableData()
}
onMounted(() => {
createColumns(variables)
getTableData()
})
watch(useI18n().locale, () => {
createColumns(variables)
})
return {
t,
...toRefs(variables),
getTableData,
onUpdatePageSize
}
},
render() {
const { getTableData, onUpdatePageSize, loadingRef } = this
return (
<NSpace vertical>
<Card>
<NSpace vertical>
<NDataTable
loading={loadingRef}
columns={this.columns}
scrollX={this.tableWidth}
data={this.tableData}
/>
<NSpace justify='center'>
<NPagination
v-model:page={this.page}
v-model:page-size={this.pageSize}
page-count={this.totalPage}
show-size-picker
page-sizes={[10, 30, 50]}
show-quick-jumper
onUpdatePage={getTableData}
onUpdatePageSize={onUpdatePageSize}
/>
</NSpace>
</NSpace>
</Card>
</NSpace>
)
}
})
export default ListErrorCommandTable
Loading…
Cancel
Save