diff --git a/src/main/java/com/ycwl/basic/integration/CLAUDE.md b/src/main/java/com/ycwl/basic/integration/CLAUDE.md index 2eb1a1e..32f8db0 100644 --- a/src/main/java/com/ycwl/basic/integration/CLAUDE.md +++ b/src/main/java/com/ycwl/basic/integration/CLAUDE.md @@ -23,6 +23,7 @@ The integration package (`com.ycwl.basic.integration`) is responsible for extern Currently implemented: - **Scenic Integration** (`com.ycwl.basic.integration.scenic`): ZT-Scenic microservice integration - **Device Integration** (`com.ycwl.basic.integration.device`): ZT-Device microservice integration +- **Render Worker Integration** (`com.ycwl.basic.integration.render`): ZT-Render-Worker microservice integration ### Integration Pattern @@ -241,6 +242,13 @@ integration: readTimeout: 10000 retryEnabled: false maxRetries: 3 + render: + enabled: true + serviceName: zt-render-worker + connectTimeout: 5000 + readTimeout: 10000 + retryEnabled: false + maxRetries: 3 ``` ### Usage Examples @@ -534,6 +542,11 @@ integration: enabled: true # Enable fallback for device service ttlDays: 5 # Custom TTL for device (shorter due to dynamic data) # cachePrefix: "device:fallback:" # Optional custom prefix + + render: + enabled: true # Enable fallback for render worker service + ttlDays: 7 # Custom TTL for render worker (medium due to stable worker data) + # cachePrefix: "render:fallback:" # Optional custom prefix # Service configurations scenic: @@ -587,6 +600,205 @@ class ScenicIntegrationServiceTest { ### Integration Testing Use `@SpringBootTest` with test profiles and mock external services. +## Render Worker Integration (ZT-Render-Worker Microservice) + +### Key Components + +#### Feign Clients +- **RenderWorkerV2Client**: Main render worker operations (CRUD, listing) +- **RenderWorkerConfigV2Client**: Render worker configuration management + +#### Services +- **RenderWorkerIntegrationService**: High-level render worker operations (with automatic fallback) +- **RenderWorkerConfigIntegrationService**: Configuration management (with automatic fallback) + +#### Configuration +```yaml +integration: + render: + enabled: true + serviceName: zt-render-worker + connectTimeout: 5000 + readTimeout: 10000 + retryEnabled: false + maxRetries: 3 +``` + +### Usage Examples + +#### Basic Render Worker Operations (with Automatic Fallback) +```java +@Autowired +private RenderWorkerIntegrationService renderWorkerService; + +// Get render worker basic info (automatically falls back to cache on failure) +RenderWorkerV2DTO worker = renderWorkerService.getWorker(workerId); + +// Get render worker with configuration (automatically falls back to cache on failure) +RenderWorkerV2WithConfigDTO workerWithConfig = renderWorkerService.getWorkerWithConfig(workerId); + +// Get render worker by key (automatically falls back to cache on failure) +RenderWorkerV2DTO workerByKey = renderWorkerService.getWorkerByKey("video-renderer-001"); + +// Get render worker with config by key (automatically falls back to cache on failure) +RenderWorkerV2WithConfigDTO workerWithConfigByKey = renderWorkerService.getWorkerWithConfigByKey("video-renderer-001"); + +// Create new render worker (direct operation, fails immediately on error) +CreateRenderWorkerRequest request = new CreateRenderWorkerRequest(); +request.setName("Video Renderer"); +request.setKey("video-renderer-001"); +request.setIsActive(1); +RenderWorkerV2DTO newWorker = renderWorkerService.createWorker(request); + +// Update render worker (direct operation, fails immediately on error) +UpdateRenderWorkerRequest updateRequest = new UpdateRenderWorkerRequest(); +updateRequest.setName("Updated Video Renderer"); +renderWorkerService.updateWorker(workerId, updateRequest); + +// Delete render worker (direct operation, fails immediately on error) +renderWorkerService.deleteWorker(workerId); + +// List render workers (no fallback for list operations) +List workers = renderWorkerService.listWorkers(1, 10, 1, null); + +// List render workers with config (no fallback for list operations) +List workersWithConfig = + renderWorkerService.listWorkersWithConfig(1, 10, 1, null); +``` + +#### Configuration Management (with Automatic Fallback) +```java +@Autowired +private RenderWorkerConfigIntegrationService configService; + +// Get worker configurations (with fallback) +List configs = configService.getWorkerConfigs(workerId); + +// Get flat configuration (automatically falls back to cache on failure) +Map flatConfig = configService.getWorkerFlatConfig(workerId); + +// Get specific configuration by key (with fallback) +RenderWorkerConfigV2DTO config = configService.getWorkerConfigByKey(workerId, "render_quality"); + +// Create configuration (direct operation, fails immediately on error) +RenderWorkerConfigV2DTO newConfig = new RenderWorkerConfigV2DTO(); +newConfig.setConfigKey("max_concurrent_tasks"); +newConfig.setConfigValue("4"); +newConfig.setConfigType("int"); +newConfig.setDescription("Maximum concurrent render tasks"); +newConfig.setIsActive(1); +RenderWorkerConfigV2DTO created = configService.createWorkerConfig(workerId, newConfig); + +// Update configuration (direct operation, fails immediately on error) +Map updates = new HashMap<>(); +updates.put("configValue", "8"); +configService.updateWorkerConfig(workerId, configId, updates); + +// Delete configuration (direct operation, fails immediately on error) +configService.deleteWorkerConfig(workerId, configId); +``` + +#### Enhanced Batch Configuration API +```java +// Using Builder Pattern for batch configuration +BatchRenderWorkerConfigRequest request = configService.createBatchConfigBuilder() + .addRenderConfig("high", "mp4", "1920x1080") // Render settings + .addPerformanceConfig(8, 3600) // Performance settings + .addConfig("output_path", "/data/renders", "string", "Output directory") + .addConfig("enable_gpu", "true", "bool", "Enable GPU acceleration") + .build(); + +// Batch update configurations (direct operation, fails immediately on error) +configService.batchUpdateWorkerConfigs(workerId, request); + +// Batch flat update configurations (direct operation, fails immediately on error) +Map flatUpdates = new HashMap<>(); +flatUpdates.put("render_quality", "ultra"); +flatUpdates.put("max_concurrent_tasks", 12); +flatUpdates.put("enable_preview", true); +configService.batchFlatUpdateWorkerConfigs(workerId, flatUpdates); +``` + +#### Render Worker Management Patterns +```java +// Create and configure render worker in one operation +CreateRenderWorkerRequest workerRequest = new CreateRenderWorkerRequest(); +workerRequest.setName("4K Video Renderer"); +workerRequest.setKey("4k-video-renderer"); +RenderWorkerV2DTO worker = renderWorkerService.createWorker(workerRequest); + +// Configure the worker for 4K video rendering +BatchRenderWorkerConfigRequest config = configService.createBatchConfigBuilder() + .addRenderConfig("ultra", "mp4", "3840x2160") + .addPerformanceConfig(4, 7200) // 4 concurrent tasks, 2 hour timeout + .addConfig("gpu_memory_limit", "8192", "int", "GPU memory limit in MB") + .addConfig("codec", "h265", "string", "Video codec") + .addConfig("bitrate", "50000", "int", "Video bitrate in kbps") + .build(); +configService.batchUpdateWorkerConfigs(worker.getId(), config); + +// Monitor worker configuration completeness (with automatic fallback) +Map workerConfig = configService.getWorkerFlatConfig(worker.getId()); +boolean hasRenderConfig = workerConfig.containsKey("render_quality"); +boolean hasPerformanceConfig = workerConfig.containsKey("max_concurrent_tasks"); +// log configuration status... + +// Get all active workers for monitoring +List activeWorkers = + renderWorkerService.listWorkersWithConfig(1, 100, 1, null); + +// Check worker health and configuration +for (RenderWorkerV2WithConfigDTO activeWorker : activeWorkers) { + Map config = activeWorker.getConfig(); + boolean isConfigured = config.containsKey("render_quality") && + config.containsKey("max_concurrent_tasks"); + // log worker status... +} +``` + +#### Fallback Cache Management for Render Workers +```java +@Autowired +private IntegrationFallbackService fallbackService; + +// Check fallback cache status +boolean hasWorkerCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:1001"); +boolean hasWorkerByKeyCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:key:video-renderer-001"); +boolean hasConfigCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:flat:config:1001"); +boolean hasConfigByKeyCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:key:config:video-renderer-001"); + +// Get cache statistics +IntegrationFallbackService.FallbackCacheStats stats = + fallbackService.getFallbackCacheStats("zt-render-worker"); +log.info("Render worker fallback cache: {} items, TTL: {} days", + stats.getTotalCacheCount(), stats.getFallbackTtlDays()); + +// Clear specific cache +fallbackService.clearFallbackCache("zt-render-worker", "worker:1001"); + +// Clear all render worker caches +fallbackService.clearAllFallbackCache("zt-render-worker"); +``` + +### Render Worker Types and Configuration + +#### Common Configuration Keys +- `render_quality`: Render quality level ("low", "medium", "high", "ultra") +- `render_format`: Output format ("mp4", "avi", "mov", "webm") +- `render_resolution`: Video resolution ("1920x1080", "3840x2160", "1280x720") +- `max_concurrent_tasks`: Maximum concurrent render tasks (integer) +- `task_timeout`: Task timeout in seconds (integer) +- `output_path`: Render output directory path (string) +- `enable_gpu`: Enable GPU acceleration (boolean) +- `gpu_memory_limit`: GPU memory limit in MB (integer) +- `codec`: Video codec ("h264", "h265", "vp9") +- `bitrate`: Video bitrate in kbps (integer) +- `enable_preview`: Enable preview generation (boolean) + +#### Worker Status +- **Active (isActive=1)**: Worker is available for tasks +- **Inactive (isActive=0)**: Worker is disabled + ## Common Development Tasks ### Running Integration Tests @@ -600,6 +812,10 @@ mvn test -Dtest="com.ycwl.basic.integration.*Test" # Run device integration tests mvn test -Dtest=DeviceIntegrationServiceTest mvn test -Dtest="com.ycwl.basic.integration.device.*Test" + +# Run render worker integration tests +mvn test -Dtest=RenderWorkerIntegrationServiceTest +mvn test -Dtest="com.ycwl.basic.integration.render.*Test" ``` ### Adding New DTOs diff --git a/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java b/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java index a25541e..aa10a5c 100644 --- a/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java +++ b/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java @@ -26,6 +26,11 @@ public class IntegrationProperties { */ private DeviceConfig device = new DeviceConfig(); + /** + * 渲染工作器服务配置 + */ + private RenderWorkerConfig render = new RenderWorkerConfig(); + @Data public static class ScenicConfig { /** @@ -98,6 +103,32 @@ public class IntegrationProperties { */ private ServiceFallbackConfig scenic = new ServiceFallbackConfig(); private ServiceFallbackConfig device = new ServiceFallbackConfig(); + private ServiceFallbackConfig render = new ServiceFallbackConfig(); + } + + @Data + public static class RenderWorkerConfig { + /** + * 是否启用渲染工作器服务集成 + */ + private boolean enabled = true; + + /** + * 服务名称 + */ + private String serviceName = "zt-render-worker"; + + /** + * 超时配置(毫秒) + */ + private int connectTimeout = 5000; + private int readTimeout = 10000; + + /** + * 重试配置 + */ + private boolean retryEnabled = false; + private int maxRetries = 3; } @Data diff --git a/src/main/java/com/ycwl/basic/integration/common/response/CommonResponse.java b/src/main/java/com/ycwl/basic/integration/common/response/CommonResponse.java index 2d7d7f1..d5d9541 100644 --- a/src/main/java/com/ycwl/basic/integration/common/response/CommonResponse.java +++ b/src/main/java/com/ycwl/basic/integration/common/response/CommonResponse.java @@ -12,29 +12,33 @@ import lombok.AllArgsConstructor; public class CommonResponse { private Integer code; private String message; + private Boolean success; private T data; public static CommonResponse success() { - return new CommonResponse<>(200, "OK", null); + return new CommonResponse<>(200, "OK", true, null); } public static CommonResponse success(T data) { - return new CommonResponse<>(200, "OK", data); + return new CommonResponse<>(200, "OK", true, data); } public static CommonResponse success(String message, T data) { - return new CommonResponse<>(200, message, data); + return new CommonResponse<>(200, message, true, data); } public static CommonResponse error(Integer code, String message) { - return new CommonResponse<>(code, message, null); + return new CommonResponse<>(code, message, false, null); } public static CommonResponse error(String message) { - return new CommonResponse<>(5000, message, null); + return new CommonResponse<>(5000, message, false, null); } public boolean isSuccess() { - return code != null && code == 200; + if (success == null) { // compatible + return code != null && code == 200; + } + return success; } } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerConfigV2Client.java b/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerConfigV2Client.java new file mode 100644 index 0000000..fa478c3 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerConfigV2Client.java @@ -0,0 +1,59 @@ +package com.ycwl.basic.integration.render.client; + +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest; +import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 渲染工作器配置V2客户端 + */ +@FeignClient(name = "zt-render-worker", contextId = "render-worker-config-v2", path = "/api/render/worker/config/v2") +public interface RenderWorkerConfigV2Client { + + /** + * 获取工作器所有配置 + */ + @GetMapping("/{workerId}") + CommonResponse> getWorkerConfigs(@PathVariable("workerId") Long workerId); + + /** + * 根据配置键获取特定配置 + */ + @GetMapping("/{workerId}/key/{configKey}") + CommonResponse getWorkerConfigByKey(@PathVariable("workerId") Long workerId, + @PathVariable("configKey") String configKey); + + /** + * 创建配置 + */ + @PostMapping("/{workerId}") + CommonResponse createWorkerConfig(@PathVariable("workerId") Long workerId, + @RequestBody RenderWorkerConfigV2DTO config); + + /** + * 更新配置 + */ + @PutMapping("/{workerId}/{id}") + CommonResponse updateWorkerConfig(@PathVariable("workerId") Long workerId, + @PathVariable("id") Long id, + @RequestBody Map updates); + + /** + * 删除配置 + */ + @DeleteMapping("/{workerId}/{id}") + CommonResponse deleteWorkerConfig(@PathVariable("workerId") Long workerId, + @PathVariable("id") Long id); + + /** + * 批量更新配置 + */ + @PostMapping("/{workerId}/batch") + CommonResponse batchUpdateWorkerConfigs(@PathVariable("workerId") Long workerId, + @RequestBody BatchRenderWorkerConfigRequest request); +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerV2Client.java b/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerV2Client.java new file mode 100644 index 0000000..b73df45 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerV2Client.java @@ -0,0 +1,76 @@ +package com.ycwl.basic.integration.render.client; + +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.integration.render.dto.worker.*; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +/** + * 渲染工作器V2客户端 + */ +@FeignClient(name = "zt-render-worker", contextId = "render-worker-v2", path = "/api/render/worker/v2") +public interface RenderWorkerV2Client { + + /** + * 获取工作器核心信息 + */ + @GetMapping("/{id}") + CommonResponse getWorker(@PathVariable("id") Long id); + + /** + * 获取工作器含配置信息 + */ + @GetMapping("/{id}/with-config") + CommonResponse getWorkerWithConfig(@PathVariable("id") Long id); + + /** + * 创建工作器 + */ + @PostMapping + CommonResponse createWorker(@RequestBody CreateRenderWorkerRequest request); + + /** + * 更新工作器 + */ + @PutMapping("/{id}") + CommonResponse updateWorker(@PathVariable("id") Long id, + @RequestBody UpdateRenderWorkerRequest request); + + /** + * 删除工作器 + */ + @DeleteMapping("/{id}") + CommonResponse deleteWorker(@PathVariable("id") Long id); + + /** + * 分页查询工作器列表(核心信息) + */ + @GetMapping + PageResponse listWorkers(@RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam(required = false) Integer isEnabled, + @RequestParam(required = false) String name); + + /** + * 分页查询工作器列表(含配置信息) + */ + @GetMapping("/with-config") + PageResponse listWorkersWithConfig( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam(required = false) Integer isEnabled, + @RequestParam(required = false) String name); + + /** + * 根据key获取工作器核心信息 + */ + @GetMapping("/key/{key}") + CommonResponse getWorkerByKey(@PathVariable("key") String key); + + /** + * 根据key获取工作器完整信息(含配置) + */ + @GetMapping("/key/{key}/with-config") + CommonResponse getWorkerWithConfigByKey(@PathVariable("key") String key); +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/config/RenderWorkerIntegrationConfig.java b/src/main/java/com/ycwl/basic/integration/render/config/RenderWorkerIntegrationConfig.java new file mode 100644 index 0000000..65e4edc --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/config/RenderWorkerIntegrationConfig.java @@ -0,0 +1,19 @@ +package com.ycwl.basic.integration.render.config; + +import com.ycwl.basic.integration.common.config.IntegrationProperties; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Configuration; + +/** + * 渲染工作器集成配置 + */ +@Configuration +@ConditionalOnProperty(prefix = "integration.render", name = "enabled", havingValue = "true", matchIfMissing = true) +@EnableFeignClients(basePackages = "com.ycwl.basic.integration.render.client") +@RequiredArgsConstructor +public class RenderWorkerIntegrationConfig { + + private final IntegrationProperties integrationProperties; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/config/BatchRenderWorkerConfigRequest.java b/src/main/java/com/ycwl/basic/integration/render/dto/config/BatchRenderWorkerConfigRequest.java new file mode 100644 index 0000000..c44f5f4 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/config/BatchRenderWorkerConfigRequest.java @@ -0,0 +1,17 @@ +package com.ycwl.basic.integration.render.dto.config; + +import lombok.Data; + +import java.util.List; + +/** + * 批量更新渲染工作器配置请求DTO + */ +@Data +public class BatchRenderWorkerConfigRequest { + + /** + * 配置列表 + */ + private List configs; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/config/RenderWorkerConfigV2DTO.java b/src/main/java/com/ycwl/basic/integration/render/dto/config/RenderWorkerConfigV2DTO.java new file mode 100644 index 0000000..1f0aaad --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/config/RenderWorkerConfigV2DTO.java @@ -0,0 +1,63 @@ +package com.ycwl.basic.integration.render.dto.config; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 渲染工作器配置DTO + */ +@Data +public class RenderWorkerConfigV2DTO { + + /** + * 配置ID + */ + private Long id; + + /** + * 工作器ID + */ + @JsonProperty("worker_id") + private Long workerId; + + /** + * 配置键 + */ + @JsonProperty("config_key") + private String configKey; + + /** + * 配置值 + */ + @JsonProperty("config_value") + private String configValue; + + /** + * 配置类型 (string/int/float/bool/json) + */ + @JsonProperty("config_type") + private String configType; + + /** + * 描述 + */ + private String description; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("is_active") + private Integer isActive; + + /** + * 创建时间 + */ + @JsonProperty("create_time") + private String createTime; + + /** + * 更新时间 + */ + @JsonProperty("update_time") + private String updateTime; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/CreateRenderWorkerRequest.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/CreateRenderWorkerRequest.java new file mode 100644 index 0000000..d7d3493 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/CreateRenderWorkerRequest.java @@ -0,0 +1,31 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 创建渲染工作器请求DTO + */ +@Data +public class CreateRenderWorkerRequest { + + /** + * 工作器名称 + */ + @NotBlank(message = "工作器名称不能为空") + private String name; + + /** + * 工作器标识 + */ + @NotBlank(message = "工作器标识不能为空") + private String key; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("is_active") + private Integer isActive = 1; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2DTO.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2DTO.java new file mode 100644 index 0000000..32745ee --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2DTO.java @@ -0,0 +1,49 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Date; + +/** + * 渲染工作器核心信息DTO + */ +@Data +public class RenderWorkerV2DTO { + + /** + * 工作器ID + */ + private Long id; + + /** + * 工作器名称 + */ + private String name; + + /** + * 工作器标识 + */ + private String key; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("is_active") + private Integer isActive; + + /** + * 创建时间 + */ + @JsonProperty("create_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + /** + * 更新时间 + */ + @JsonProperty("update_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2ListResponse.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2ListResponse.java new file mode 100644 index 0000000..a70d365 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2ListResponse.java @@ -0,0 +1,33 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import lombok.Data; + +import java.util.List; + +/** + * 渲染工作器列表响应DTO + */ +@Data +public class RenderWorkerV2ListResponse { + + /** + * 工作器列表 + */ + private List list; + + /** + * 总数 + */ + private String total; + + /** + * 当前页 + */ + private Integer page; + + /** + * 页大小 + */ + @SuppressWarnings("unused") + private Integer pageSize; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigDTO.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigDTO.java new file mode 100644 index 0000000..e3bb5d6 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigDTO.java @@ -0,0 +1,55 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 带配置的渲染工作器DTO + */ +@Data +public class RenderWorkerV2WithConfigDTO { + + /** + * 工作器ID + */ + private Long id; + + /** + * 工作器名称 + */ + private String name; + + /** + * 工作器标识 + */ + private String key; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("is_active") + private Integer isActive; + + /** + * 创建时间 + */ + @JsonProperty("create_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + /** + * 更新时间 + */ + @JsonProperty("update_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + + /** + * 动态配置信息 + */ + private Map config; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigListResponse.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigListResponse.java new file mode 100644 index 0000000..e326742 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigListResponse.java @@ -0,0 +1,33 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import lombok.Data; + +import java.util.List; + +/** + * 带配置的渲染工作器列表响应DTO + */ +@Data +public class RenderWorkerV2WithConfigListResponse { + + /** + * 工作器列表 + */ + private List list; + + /** + * 总数 + */ + private String total; + + /** + * 当前页 + */ + private Integer page; + + /** + * 页大小 + */ + @SuppressWarnings("unused") + private Integer pageSize; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/UpdateRenderWorkerRequest.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/UpdateRenderWorkerRequest.java new file mode 100644 index 0000000..6c879b1 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/UpdateRenderWorkerRequest.java @@ -0,0 +1,27 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 更新渲染工作器请求DTO + */ +@Data +public class UpdateRenderWorkerRequest { + + /** + * 工作器名称 + */ + private String name; + + /** + * 工作器标识 + */ + private String key; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("is_active") + private Integer isActive; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerConfigIntegrationService.java b/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerConfigIntegrationService.java new file mode 100644 index 0000000..0fbe084 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerConfigIntegrationService.java @@ -0,0 +1,287 @@ +package com.ycwl.basic.integration.render.service; + +import com.ycwl.basic.integration.common.exception.IntegrationException; +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.service.IntegrationFallbackService; +import com.ycwl.basic.integration.render.client.RenderWorkerConfigV2Client; +import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest; +import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 渲染工作器配置集成服务 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class RenderWorkerConfigIntegrationService { + + private final RenderWorkerConfigV2Client renderWorkerConfigV2Client; + private final IntegrationFallbackService fallbackService; + + private static final String SERVICE_NAME = "zt-render-worker"; + + /** + * 获取工作器所有配置(带降级) + */ + public List getWorkerConfigs(Long workerId) { + log.info("获取渲染工作器配置列表, workerId: {}", workerId); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:configs:" + workerId, + () -> { + CommonResponse> response = + renderWorkerConfigV2Client.getWorkerConfigs(workerId); + List configs = handleResponse(response, "获取渲染工作器配置列表失败"); + return configs != null ? configs : Collections.emptyList(); + }, + List.class + ); + } + + /** + * 根据配置键获取特定配置(带降级) + */ + public RenderWorkerConfigV2DTO getWorkerConfigByKey(Long workerId, String configKey) { + log.info("根据配置键获取渲染工作器配置, workerId: {}, configKey: {}", workerId, configKey); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:config:" + workerId + ":" + configKey, + () -> { + CommonResponse response = + renderWorkerConfigV2Client.getWorkerConfigByKey(workerId, configKey); + return handleResponse(response, "根据配置键获取渲染工作器配置失败"); + }, + RenderWorkerConfigV2DTO.class + ); + } + + /** + * 获取工作器平铺配置(带降级) + */ + public Map getWorkerFlatConfig(Long workerId) { + log.info("获取渲染工作器平铺配置, workerId: {}", workerId); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:flat:config:" + workerId, + () -> { + List configs = getWorkerConfigsInternal(workerId); + return flattenConfigs(configs); + }, + Map.class + ); + } + + /** + * 创建配置(直接调用,不降级) + */ + public RenderWorkerConfigV2DTO createWorkerConfig(Long workerId, RenderWorkerConfigV2DTO config) { + log.info("创建渲染工作器配置, workerId: {}, configKey: {}", workerId, config.getConfigKey()); + CommonResponse response = + renderWorkerConfigV2Client.createWorkerConfig(workerId, config); + return handleResponse(response, "创建渲染工作器配置失败"); + } + + /** + * 更新配置(直接调用,不降级) + */ + public void updateWorkerConfig(Long workerId, Long configId, Map updates) { + log.info("更新渲染工作器配置, workerId: {}, configId: {}", workerId, configId); + CommonResponse response = + renderWorkerConfigV2Client.updateWorkerConfig(workerId, configId, updates); + handleVoidResponse(response, "更新渲染工作器配置失败"); + } + + /** + * 删除配置(直接调用,不降级) + */ + public void deleteWorkerConfig(Long workerId, Long configId) { + log.info("删除渲染工作器配置, workerId: {}, configId: {}", workerId, configId); + CommonResponse response = + renderWorkerConfigV2Client.deleteWorkerConfig(workerId, configId); + handleVoidResponse(response, "删除渲染工作器配置失败"); + } + + /** + * 批量更新配置(直接调用,不降级) + */ + public void batchUpdateWorkerConfigs(Long workerId, BatchRenderWorkerConfigRequest request) { + log.info("批量更新渲染工作器配置, workerId: {}, configCount: {}", + workerId, request.getConfigs() != null ? request.getConfigs().size() : 0); + CommonResponse response = + renderWorkerConfigV2Client.batchUpdateWorkerConfigs(workerId, request); + handleVoidResponse(response, "批量更新渲染工作器配置失败"); + } + + /** + * 批量平铺更新配置(直接调用,不降级) + */ + public void batchFlatUpdateWorkerConfigs(Long workerId, Map flatConfigs) { + log.info("批量平铺更新渲染工作器配置, workerId: {}, configCount: {}", + workerId, flatConfigs.size()); + + BatchRenderWorkerConfigRequest request = new BatchRenderWorkerConfigRequest(); + List configs = flatConfigs.entrySet().stream() + .map(entry -> { + RenderWorkerConfigV2DTO config = new RenderWorkerConfigV2DTO(); + config.setConfigKey(entry.getKey()); + config.setConfigValue(String.valueOf(entry.getValue())); + config.setConfigType(determineConfigType(entry.getValue())); + config.setIsActive(1); + return config; + }) + .toList(); + + request.setConfigs(configs); + batchUpdateWorkerConfigs(workerId, request); + } + + /** + * 创建批量配置构建器 + */ + public BatchConfigBuilder createBatchConfigBuilder() { + return new BatchConfigBuilder(); + } + + /** + * 内部获取配置方法(不使用降级) + */ + private List getWorkerConfigsInternal(Long workerId) { + CommonResponse> response = + renderWorkerConfigV2Client.getWorkerConfigs(workerId); + List configs = handleResponse(response, "获取渲染工作器配置列表失败"); + return configs != null ? configs : Collections.emptyList(); + } + + /** + * 将配置列表转换为平铺Map + */ + private Map flattenConfigs(List configs) { + Map flatConfig = new HashMap<>(); + for (RenderWorkerConfigV2DTO config : configs) { + if (config.getIsActive() == 1) { + Object value = convertConfigValue(config.getConfigValue(), config.getConfigType()); + flatConfig.put(config.getConfigKey(), value); + } + } + return flatConfig; + } + + /** + * 根据配置类型转换配置值 + */ + private Object convertConfigValue(String configValue, String configType) { + if (configValue == null) return null; + + return switch (configType) { + case "int" -> Integer.parseInt(configValue); + case "float" -> Double.parseDouble(configValue); + case "bool" -> Boolean.parseBoolean(configValue); + case "json" -> configValue; // 保持JSON字符串格式 + default -> configValue; // string类型或其他 + }; + } + + /** + * 自动判断配置类型 + */ + private String determineConfigType(Object value) { + if (value instanceof Integer) return "int"; + if (value instanceof Double || value instanceof Float) return "float"; + if (value instanceof Boolean) return "bool"; + return "string"; + } + + /** + * 处理通用响应 + */ + private T handleResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + return response.getData(); + } + + /** + * 处理空响应 + */ + private void handleVoidResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + } + + /** + * 批量配置构建器 + */ + public static class BatchConfigBuilder { + private final List configs = new java.util.ArrayList<>(); + + /** + * 添加配置项 + */ + public BatchConfigBuilder addConfig(String key, String value) { + return addConfig(key, value, "string", null); + } + + /** + * 添加配置项(指定类型) + */ + public BatchConfigBuilder addConfig(String key, String value, String type) { + return addConfig(key, value, type, null); + } + + /** + * 添加配置项(完整) + */ + public BatchConfigBuilder addConfig(String key, String value, String type, String description) { + RenderWorkerConfigV2DTO config = new RenderWorkerConfigV2DTO(); + config.setConfigKey(key); + config.setConfigValue(value); + config.setConfigType(type); + config.setDescription(description); + config.setIsActive(1); + configs.add(config); + return this; + } + + /** + * 添加渲染配置 + */ + public BatchConfigBuilder addRenderConfig(String quality, String format, String resolution) { + return addConfig("render_quality", quality, "string", "渲染质量") + .addConfig("render_format", format, "string", "渲染格式") + .addConfig("render_resolution", resolution, "string", "渲染分辨率"); + } + + /** + * 添加性能配置 + */ + public BatchConfigBuilder addPerformanceConfig(Integer maxTasks, Integer timeout) { + return addConfig("max_concurrent_tasks", String.valueOf(maxTasks), "int", "最大并发任务数") + .addConfig("task_timeout", String.valueOf(timeout), "int", "任务超时时间(秒)"); + } + + /** + * 构建批量配置请求 + */ + public BatchRenderWorkerConfigRequest build() { + BatchRenderWorkerConfigRequest request = new BatchRenderWorkerConfigRequest(); + request.setConfigs(configs); + return request; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerIntegrationService.java b/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerIntegrationService.java new file mode 100644 index 0000000..e33920a --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerIntegrationService.java @@ -0,0 +1,195 @@ +package com.ycwl.basic.integration.render.service; + +import com.ycwl.basic.integration.common.exception.IntegrationException; +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.integration.common.service.IntegrationFallbackService; +import com.ycwl.basic.integration.render.client.RenderWorkerV2Client; +import com.ycwl.basic.integration.render.dto.worker.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +/** + * 渲染工作器集成服务 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class RenderWorkerIntegrationService { + + private final RenderWorkerV2Client renderWorkerV2Client; + private final IntegrationFallbackService fallbackService; + + private static final String SERVICE_NAME = "zt-render-worker"; + + /** + * 获取工作器核心信息(带降级) + */ + public RenderWorkerV2DTO getWorker(Long id) { + log.info("获取渲染工作器信息, id: {}", id); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:" + id, + () -> { + CommonResponse response = renderWorkerV2Client.getWorker(id); + return handleResponse(response, "获取渲染工作器信息失败"); + }, + RenderWorkerV2DTO.class + ); + } + + /** + * 获取工作器详细信息(含配置)(带降级) + */ + public RenderWorkerV2WithConfigDTO getWorkerWithConfig(Long id) { + log.info("获取渲染工作器详细信息, id: {}", id); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:config:" + id, + () -> { + CommonResponse response = renderWorkerV2Client.getWorkerWithConfig(id); + return handleResponse(response, "获取渲染工作器详细信息失败"); + }, + RenderWorkerV2WithConfigDTO.class + ); + } + + /** + * 创建工作器(直接调用,不降级) + */ + public RenderWorkerV2DTO createWorker(CreateRenderWorkerRequest request) { + log.info("创建渲染工作器, name: {}, key: {}", request.getName(), request.getKey()); + CommonResponse response = renderWorkerV2Client.createWorker(request); + return handleResponse(response, "创建渲染工作器失败"); + } + + /** + * 更新工作器(直接调用,不降级) + */ + public void updateWorker(Long id, UpdateRenderWorkerRequest request) { + log.info("更新渲染工作器, id: {}, name: {}", id, request.getName()); + CommonResponse response = renderWorkerV2Client.updateWorker(id, request); + handleVoidResponse(response, "更新渲染工作器失败"); + } + + /** + * 删除工作器(直接调用,不降级) + */ + public void deleteWorker(Long id) { + log.info("删除渲染工作器, id: {}", id); + CommonResponse response = renderWorkerV2Client.deleteWorker(id); + handleVoidResponse(response, "删除渲染工作器失败"); + } + + /** + * 分页查询工作器列表(核心信息)(不降级) + */ + public List listWorkers(Integer page, Integer pageSize, Integer isEnabled, String name) { + log.info("分页查询渲染工作器列表, page: {}, pageSize: {}, isEnabled: {}, name: {}", + page, pageSize, isEnabled, name); + try { + PageResponse response = + renderWorkerV2Client.listWorkers(page, pageSize, isEnabled, name); + RenderWorkerV2ListResponse listResponse = handlePageResponse(response, "查询渲染工作器列表失败"); + return listResponse != null && listResponse.getList() != null ? + listResponse.getList() : Collections.emptyList(); + } catch (Exception e) { + log.error("查询渲染工作器列表异常", e); + return Collections.emptyList(); + } + } + + /** + * 分页查询工作器列表(含配置信息)(不降级) + */ + public List listWorkersWithConfig(Integer page, Integer pageSize, + Integer isEnabled, String name) { + log.info("分页查询渲染工作器列表(含配置), page: {}, pageSize: {}, isEnabled: {}, name: {}", + page, pageSize, isEnabled, name); + try { + PageResponse response = + renderWorkerV2Client.listWorkersWithConfig(page, pageSize, isEnabled, name); + RenderWorkerV2WithConfigListResponse listResponse = + handlePageResponse(response, "查询渲染工作器列表(含配置)失败"); + return listResponse != null && listResponse.getList() != null ? + listResponse.getList() : Collections.emptyList(); + } catch (Exception e) { + log.error("查询渲染工作器列表(含配置)异常", e); + return Collections.emptyList(); + } + } + + /** + * 根据key获取工作器核心信息(带降级) + */ + public RenderWorkerV2DTO getWorkerByKey(String key) { + log.info("根据key获取渲染工作器信息, key: {}", key); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:key:" + key, + () -> { + CommonResponse response = renderWorkerV2Client.getWorkerByKey(key); + return handleResponse(response, "根据key获取渲染工作器信息失败"); + }, + RenderWorkerV2DTO.class + ); + } + + /** + * 根据key获取工作器详细信息(含配置)(带降级) + */ + public RenderWorkerV2WithConfigDTO getWorkerWithConfigByKey(String key) { + log.info("根据key获取渲染工作器详细信息, key: {}", key); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:key:config:" + key, + () -> { + CommonResponse response = renderWorkerV2Client.getWorkerWithConfigByKey(key); + return handleResponse(response, "根据key获取渲染工作器详细信息失败"); + }, + RenderWorkerV2WithConfigDTO.class + ); + } + + /** + * 处理通用响应 + */ + private T handleResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + return response.getData(); + } + + /** + * 处理空响应 + */ + private void handleVoidResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + } + + /** + * 处理分页响应 + */ + private T handlePageResponse(PageResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + return response.getData(); + } +} \ No newline at end of file