diff --git a/examples/fit-example/08-nacos-complicated-apps/app-assistant/pom.xml b/examples/fit-example/08-nacos-complicated-apps/app-assistant/pom.xml new file mode 100644 index 00000000..5251602c --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/app-assistant/pom.xml @@ -0,0 +1,116 @@ + + + 4.0.0 + + org.fitframework.example + nacos-assistant-for-complicated + 1.0-SNAPSHOT + + + UTF-8 + 17 + + + 3.6.0-SNAPSHOT + + + 3.14.0 + + + + + org.fitframework.example + nacos-weather-for-complicated + 1.0-SNAPSHOT + + + org.fitframework + fit-starter + ${fit.version} + + + + + org.fitframework + fit-plugins-starter-web + ${fit.version} + + + + + org.fitframework.plugin + fit-client-http + ${fit.version} + runtime + + + org.fitframework.plugin + fit-http-client-okhttp + ${fit.version} + runtime + + + org.fitframework.plugin + fit-heartbeat-client + ${fit.version} + runtime + + + org.fitframework.plugin + fit-service-registry + ${fit.version} + runtime + + + org.fitframework.plugin + fit-service-discovery + ${fit.version} + runtime + + + org.fitframework.plugin + fit-service-coordination-locator + ${fit.version} + runtime + + + + org.fitframework.plugin + fit-service-coordination-nacos + ${fit.version} + runtime + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.version} + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + -parameters + + + + + org.fitframework + fit-build-maven-plugin + ${fit.version} + + + package-app + + package-app + + + + + + + \ No newline at end of file diff --git a/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/java/modelengine/fit/example/AssistantStarter.java b/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/java/modelengine/fit/example/AssistantStarter.java new file mode 100644 index 00000000..5adec082 --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/java/modelengine/fit/example/AssistantStarter.java @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.example; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.ScanPackages; +import modelengine.fitframework.runtime.FitStarter; + +/** + * 启动类。 + * + * @author 董智豪 + * @since 2025-06-21 + */ +@Component +@ScanPackages("modelengine") +public class AssistantStarter { + public static void main(String[] args) { + FitStarter.start(AssistantStarter.class, args); + } +} diff --git a/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java b/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java new file mode 100644 index 00000000..8bc50aac --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.example.controller; + +import modelengine.fit.example.Weather; +import modelengine.fit.http.annotation.GetMapping; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Fit; + +/** + * 表示助手的控制器。 + * + * @author 董智豪 + * @since 2025-06-21 + */ +@Component +public class AssistantController { + private final Weather weather; + + public AssistantController(@Fit Weather weather) { + this.weather = weather; + } + + /** + * 获取天气信息。 + * + * @return 表示天气信息的 {@link String}。 + */ + @GetMapping(path = "/weather") + public String getWeather() { + return this.weather.get(); + } +} diff --git a/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/resources/application.yml b/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/resources/application.yml new file mode 100644 index 00000000..a97d7939 --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/app-assistant/src/main/resources/application.yml @@ -0,0 +1,19 @@ +application: + name: 'assistant' + +worker: + id: 'assistant' + host: '127.0.0.1' + environment: 'local' + environment-sequence: 'local' + +matata: + registry: + mode: 'PROXY' + host: '127.0.0.1' + port: 8848 + environment: 'local' + +server: + http: + port: 8080 \ No newline at end of file diff --git a/examples/fit-example/08-nacos-complicated-apps/app-default-weather/pom.xml b/examples/fit-example/08-nacos-complicated-apps/app-default-weather/pom.xml new file mode 100644 index 00000000..116e3a5a --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/app-default-weather/pom.xml @@ -0,0 +1,115 @@ + + + 4.0.0 + + org.fitframework.example + nacos-default-weather-for-complicated + 1.0-SNAPSHOT + + + UTF-8 + 17 + + + 3.6.0-SNAPSHOT + + + 3.14.0 + + + + + org.fitframework.example + nacos-weather-for-complicated + 1.0-SNAPSHOT + + + org.fitframework + fit-starter + ${fit.version} + + + + + org.fitframework + fit-plugins-starter-web + ${fit.version} + + + + + org.fitframework.plugin + fit-client-http + ${fit.version} + runtime + + + org.fitframework.plugin + fit-http-client-okhttp + ${fit.version} + runtime + + + org.fitframework.plugin + fit-heartbeat-client + ${fit.version} + runtime + + + org.fitframework.plugin + fit-service-registry + ${fit.version} + runtime + + + org.fitframework.plugin + fit-service-discovery + ${fit.version} + runtime + + + org.fitframework.plugin + fit-service-coordination-locator + ${fit.version} + runtime + + + org.fitframework.plugin + fit-service-coordination-nacos + ${fit.version} + runtime + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.version} + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + -parameters + + + + + org.fitframework + fit-build-maven-plugin + ${fit.version} + + + package-app + + package-app + + + + + + + \ No newline at end of file diff --git a/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/java/modelengine/fit/example/DefaultWeather.java b/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/java/modelengine/fit/example/DefaultWeather.java new file mode 100644 index 00000000..8f441da1 --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/java/modelengine/fit/example/DefaultWeather.java @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.example; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Fitable; + +/** + * 表示 {@link Weather} 的默认实现。 + * + * @author 董智豪 + * @since 2025-06-21 + */ +@Component +public class DefaultWeather implements Weather { + @Override + @Fitable(id = "default-weather") + public String get() { + return "Default weather application is working."; + } +} diff --git a/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/java/modelengine/fit/example/DefaultWeatherStarter.java b/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/java/modelengine/fit/example/DefaultWeatherStarter.java new file mode 100644 index 00000000..94c797f2 --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/java/modelengine/fit/example/DefaultWeatherStarter.java @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.example; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.ScanPackages; +import modelengine.fitframework.runtime.FitStarter; + +/** + * 启动类。 + * + * @author 董智豪 + * @since 2025-06-21 + */ +@Component +@ScanPackages("modelengine") +public class DefaultWeatherStarter { + public static void main(String[] args) { + FitStarter.start(DefaultWeatherStarter.class, args); + } +} diff --git a/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/resources/application.yml b/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/resources/application.yml new file mode 100644 index 00000000..035e846d --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/app-default-weather/src/main/resources/application.yml @@ -0,0 +1,19 @@ +application: + name: 'default-weather' + +worker: + id: 'default-weather' + host: '127.0.0.1' + environment: 'local' + environment-sequence: 'local' + +matata: + registry: + mode: 'PROXY' + host: '127.0.0.1' + port: 8848 + environment: 'local' + +server: + http: + port: 8081 \ No newline at end of file diff --git a/examples/fit-example/08-nacos-complicated-apps/pom.xml b/examples/fit-example/08-nacos-complicated-apps/pom.xml new file mode 100644 index 00000000..e0a4848f --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + org.fitframework.example + nacos-complicated-apps + 1.0-SNAPSHOT + pom + + + app-assistant + app-default-weather + service + + \ No newline at end of file diff --git a/examples/fit-example/08-nacos-complicated-apps/service/pom.xml b/examples/fit-example/08-nacos-complicated-apps/service/pom.xml new file mode 100644 index 00000000..9e52396c --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/service/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + org.fitframework.example + nacos-weather-for-complicated + 1.0-SNAPSHOT + + + UTF-8 + 17 + + + 3.6.0-SNAPSHOT + + + 3.14.0 + + + + + org.fitframework + fit-api + ${fit.version} + + + org.fitframework + fit-util + ${fit.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.version} + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + -parameters + + + + + org.fitframework + fit-build-maven-plugin + ${fit.version} + + + build-service + + build-service + + + + + + + \ No newline at end of file diff --git a/examples/fit-example/08-nacos-complicated-apps/service/src/main/java/modelengine/fit/example/Weather.java b/examples/fit-example/08-nacos-complicated-apps/service/src/main/java/modelengine/fit/example/Weather.java new file mode 100644 index 00000000..3f1581a5 --- /dev/null +++ b/examples/fit-example/08-nacos-complicated-apps/service/src/main/java/modelengine/fit/example/Weather.java @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.example; + +import modelengine.fitframework.annotation.Genericable; + +/** + * 表示通用接口服务。 + * + * @author 董智豪 + * @since 2025-06-21 + */ +public interface Weather { + /** + * 获取天气信息。 + * + * @return 表示天气信息的 {@link String}。 + */ + @Genericable(id = "Weather") + String get(); +} diff --git a/examples/fit-example/pom.xml b/examples/fit-example/pom.xml index 769be155..080850cc 100644 --- a/examples/fit-example/pom.xml +++ b/examples/fit-example/pom.xml @@ -16,5 +16,6 @@ 05-aop-log-plugin 06-spring-boot-starter 07-http-client-proxy + 08-nacos-complicated-apps diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/conf/runtime/MatataConfig.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/conf/runtime/MatataConfig.java index 808c9b56..9852075e 100644 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/conf/runtime/MatataConfig.java +++ b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/conf/runtime/MatataConfig.java @@ -36,6 +36,13 @@ interface Registry { */ String host(); + /** + * 获取 {@code 'matata.registry.mode'} 的配置项。 + * + * @return 表示 {@code 'matata.registry.mode'} 的配置项的 {@link RegistryConnectMode}。 + */ + RegistryConnectMode mode(); + /** * 获取 {@code 'matata.registry.port'} 的配置项。 * @@ -199,4 +206,4 @@ interface SecureAccess { String secretKey(); } } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/conf/runtime/RegistryConnectMode.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/conf/runtime/RegistryConnectMode.java new file mode 100644 index 00000000..5eff26e7 --- /dev/null +++ b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/conf/runtime/RegistryConnectMode.java @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.conf.runtime; + +import static modelengine.fitframework.inspection.Validation.notBlank; + +import modelengine.fitframework.util.StringUtils; + +import java.util.Arrays; + +/** + * 注册中心连接模式枚举,用于标识客户端连接注册中心的方式。 + * + *

支持的连接模式包括:

+ * + * + * @author 董智豪 + * @since 2025-08-04 + */ +public enum RegistryConnectMode { + /** 直连注册中心模式(不经过代理)。 */ + DIRECT("DIRECT"), + + /** 通过代理连接注册中心(例如本地 Socks/HTTP 代理)。 */ + PROXY("PROXY"); + + /** 模式标识符字符串(如:DIRECT、PROXY)。 */ + private final String mode; + + /** + * 构造函数,初始化连接模式标识符。 + * + * @param mode 注册中心连接模式的标识符(不能为空)。 + */ + RegistryConnectMode(String mode) { + this.mode = notBlank(mode, "The registry connect mode cannot be blank."); + } + + /** + * 根据字符串标识获取对应的枚举值。 + * + * @param mode 字符串标识(如 "DIRECT"、"PROXY")。 + * @return 匹配的 {@link RegistryConnectMode} 枚举值;如果无匹配项则返回 {@code DIRECT},默认为直连模式。 + */ + public static RegistryConnectMode fromMode(String mode) { + return Arrays.stream(RegistryConnectMode.values()) + .filter(registryConnectMode -> StringUtils.equals(registryConnectMode.mode, mode)) + .findFirst() + .orElse(DIRECT); + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-locator/src/main/java/modelengine/fit/service/locator/AddressRepository.java b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-locator/src/main/java/modelengine/fit/service/locator/AddressRepository.java index b8e3e77c..173a9b39 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-locator/src/main/java/modelengine/fit/service/locator/AddressRepository.java +++ b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-locator/src/main/java/modelengine/fit/service/locator/AddressRepository.java @@ -6,6 +6,8 @@ package modelengine.fit.service.locator; +import static modelengine.fitframework.conf.runtime.RegistryConnectMode.PROXY; +import static modelengine.fitframework.inspection.Validation.greaterThan; import static modelengine.fitframework.inspection.Validation.notNull; import modelengine.fit.server.FitServer; @@ -13,6 +15,7 @@ import modelengine.fitframework.annotation.Component; import modelengine.fitframework.broker.Endpoint; import modelengine.fitframework.broker.Target; +import modelengine.fitframework.conf.runtime.CommunicationProtocol; import modelengine.fitframework.conf.runtime.MatataConfig; import modelengine.fitframework.conf.runtime.WorkerConfig; import modelengine.fitframework.log.Logger; @@ -41,25 +44,38 @@ public class AddressRepository implements RegistryLocator { * @param servers 表示 FIT 的服务器的列表的 {@link List}{@code <}{@link FitServer}{@code >}。 * @param worker 表示进程配置的 {@link WorkerConfig}。 * @param matata 表示 matata 配置的 {@link MatataConfig}。 + * @param fitServer 表示 FIT 服务器的 {@link FitServer}。 */ - public AddressRepository(List servers, WorkerConfig worker, MatataConfig matata) { + public AddressRepository(List servers, WorkerConfig worker, MatataConfig matata, FitServer fitServer) { List actualServers = ObjectUtils.getIfNull(servers, Collections::emptyList); notNull(worker, "The worker config cannot be null."); notNull(matata, "The matata config cannot be null."); - boolean isRegistryLocalhost = isRegistryLocalhost(actualServers, - worker.host(), - worker.domain(), - matata.registry().host(), - matata.registry().port(), - matata.registry().protocolCode()); - String registryWorkerId = - isRegistryLocalhost ? worker.id() : matata.registry().host() + ":" + matata.registry().port(); + notNull(fitServer, "The fitserver cannot be null."); + int port = matata.registry().port(); + int protocolCode = matata.registry().protocolCode(); + CommunicationProtocol protocol = matata.registry().protocol(); + String host = matata.registry().host(); + + if (PROXY == matata.registry().mode()) { + log.debug("The registry mode is Nacos, using the local proxy registry center."); + int size = fitServer.endpoints().size(); + greaterThan(size, 0, "The fit server must have at least one endpoint."); + Endpoint endpoint = fitServer.endpoints().get(0); + port = endpoint.port(); + protocolCode = endpoint.protocolCode(); + protocol = CommunicationProtocol.from(endpoint.protocol()); + host = worker.host(); + } + + boolean isRegistryLocalhost = + isRegistryLocalhost(actualServers, worker.host(), worker.domain(), host, port, protocolCode); + String registryWorkerId = isRegistryLocalhost ? worker.id() : host + ":" + port; this.registryTarget = Target.custom() .workerId(registryWorkerId) - .host(matata.registry().host()) + .host(host) .endpoints(Collections.singletonList(Endpoint.custom() - .port(matata.registry().port()) - .protocol(matata.registry().protocol().name(), matata.registry().protocolCode()) + .port(port) + .protocol(protocol.name(), protocolCode) .build())) .environment(matata.registry().environment()) .extensions(matata.registry().visualExtensions()) diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/pom.xml new file mode 100644 index 00000000..48c2f398 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + + org.fitframework.plugin + fit-plugin-parent + 3.6.0-SNAPSHOT + + + fit-service-coordination-nacos + + FIT Service Coordination Nacos + FIT Framework Service Coordination Nacos Plugin module provides a nacos-based implementation of FIT + service registry center. + + https://github.com/ModelEngine-Group/fit-framework + + + + + org.fitframework + fit-api + + + org.fitframework + fit-util + + + + + org.fitframework.service + fit-heartbeat + + + org.fitframework.service + fit-service-registry-and-discovery + + + org.fitframework.service + fit-http-classic + + + + + org.projectlombok + lombok + + + com.alibaba.nacos + nacos-client + + + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + org.assertj + assertj-core + test + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + package + + + + + + + run + + + + + + + \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/heartbeat/server/HeartbeatServer.java b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/heartbeat/server/HeartbeatServer.java new file mode 100644 index 00000000..424ccfe4 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/heartbeat/server/HeartbeatServer.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.heartbeat.server; + +import modelengine.fit.heartbeat.HeartbeatService; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Fitable; + +import java.util.List; + +/** + * Service for providing heartbeat-related functionality. + * + * @author 董智豪 + * @since 2025-06-04 + */ +@Component +public class HeartbeatServer implements HeartbeatService { + @Override + @Fitable(id = "send-heartbeat") + public Boolean sendHeartbeat(List heartbeatInfo, Address address) { + return true; + } + + @Override + @Fitable(id = "stop-heartbeat") + public Boolean stopHeartbeat(List heartbeatInfo, Address address) { + return true; + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/service/server/NacosConfig.java b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/service/server/NacosConfig.java new file mode 100644 index 00000000..d7c78d72 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/service/server/NacosConfig.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.service.server; + +import lombok.Data; + +/** + * Represents the configuration prefixed with {@code 'matata.registry.nacos.'}. + * + * @author 董智豪 + * @since 2025-08-06 + */ +@Data +public class NacosConfig { + /** + * Login username for Nacos authentication. + * Required when Nacos server has authentication enabled. + */ + private String username; + + /** + * Login password for Nacos authentication. + * Used together with username for authentication when connecting to secured Nacos server. + */ + private String password; + + /** + * Access key for Nacos authentication. + * Used for access control in cloud environments or when using AK/SK authentication. + */ + private String accessKey; + + /** + * Secret key for Nacos authentication. + * Used together with access key for AK/SK authentication mechanism. + */ + private String secretKey; + + /** + * Whether it is an ephemeral instance. + * Ephemeral instances will be automatically removed from the registry after service deregistration. + */ + private Boolean isEphemeral; + + /** + * Service weight. + * Used for weight calculation during load balancing. + */ + private Float weight; + + /** + * Heartbeat interval time (unit: milliseconds). + * Defines the time interval for services to send heartbeats. + */ + private Long heartbeatInterval; + + /** + * Heartbeat timeout time (unit: milliseconds). + * Defines the time after which a service is considered timed out when no heartbeat is received. + */ + private Long heartbeatTimeout; +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/service/server/NacosRegistryServer.java b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/service/server/NacosRegistryServer.java new file mode 100644 index 00000000..3262a1d7 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/java/modelengine/fit/service/server/NacosRegistryServer.java @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.service.server; + +import static com.alibaba.nacos.api.naming.PreservedMetadataKeys.HEART_BEAT_INTERVAL; +import static com.alibaba.nacos.api.naming.PreservedMetadataKeys.HEART_BEAT_TIMEOUT; +import static modelengine.fitframework.inspection.Validation.notBlank; +import static modelengine.fitframework.inspection.Validation.notNull; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingFactory; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.EventListener; +import com.alibaba.nacos.api.naming.listener.NamingEvent; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ListView; +import com.alibaba.nacos.client.naming.listener.NamingChangeEvent; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import modelengine.fit.service.Notify; +import modelengine.fit.service.RegistryService; +import modelengine.fit.service.entity.Address; +import modelengine.fit.service.entity.Application; +import modelengine.fit.service.entity.ApplicationInstance; +import modelengine.fit.service.entity.Endpoint; +import modelengine.fit.service.entity.FitableAddressInstance; +import modelengine.fit.service.entity.FitableInfo; +import modelengine.fit.service.entity.FitableMeta; +import modelengine.fit.service.entity.FitableMetaInstance; +import modelengine.fit.service.entity.GenericableInfo; +import modelengine.fit.service.entity.Worker; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Fitable; +import modelengine.fitframework.conf.Config; +import modelengine.fitframework.conf.runtime.CommunicationProtocol; +import modelengine.fitframework.conf.runtime.MatataConfig; +import modelengine.fitframework.conf.runtime.WorkerConfig; +import modelengine.fitframework.log.Logger; +import modelengine.fitframework.util.ObjectUtils; +import modelengine.fitframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Service for providing Nacos registry center functionality. + * + * @author 董智豪 + * @since 2025-06-04 + */ +@Component +public class NacosRegistryServer implements RegistryService { + private static final Logger log = Logger.get(NacosRegistryServer.class); + private static final String CLUSTER_DOMAIN_KEY = "cluster.domain"; + private static final Pattern CLUSTER_PORT_PATTERN = Pattern.compile("cluster\\.(.*?)\\.port"); + private static final String WORKER_KEY = "worker"; + private static final String APPLICATION_KEY = "application"; + private static final String FITABLE_META_KEY = "fitable-meta"; + private static final String SEPARATOR = "::"; + + private final NamingService namingService; + private final ObjectMapper objectMapper = new ObjectMapper(); + private final NacosConfig nacosConfig; + private final MatataConfig matata; + private final Notify notify; + private final WorkerConfig worker; + private final Map serviceSubscriptions = + new ConcurrentHashMap<>(); + + public NacosRegistryServer(Notify notify, WorkerConfig worker, Config config,MatataConfig matata) + throws NacosException { + notNull(config, "The configuration cannot be null."); + this.matata = notNull(matata, "The matata configuration cannot be null."); + this.notify = notNull(notify, "The registry listener cannot be null."); + this.worker = notNull(worker, "The worker config cannot be null."); + this.nacosConfig = config.get("matata.registry.nacos", NacosConfig.class); + this.namingService = NamingFactory.createNamingService(getNacosProperties()); + } + + private Properties getNacosProperties() { + Properties properties = new Properties(); + String serverAddr = this.matata.registry().host() + ":" + this.matata.registry().port(); + notBlank(serverAddr, "The Nacos server address cannot be blank."); + properties.put("serverAddr", serverAddr); + properties.put("username", ObjectUtils.nullIf(this.nacosConfig.getUsername(), StringUtils.EMPTY)); + properties.put("password", ObjectUtils.nullIf(this.nacosConfig.getPassword(), StringUtils.EMPTY)); + properties.put("namespace", ObjectUtils.nullIf(this.matata.registry().environment(), StringUtils.EMPTY)); + properties.put("accessKey", ObjectUtils.nullIf(this.nacosConfig.getAccessKey(), StringUtils.EMPTY)); + properties.put("secretKey", ObjectUtils.nullIf(this.nacosConfig.getSecretKey(), StringUtils.EMPTY)); + return properties; + } + + /** + * Builds a unique key in the format {@code ::} for {@code }. + * + * @param groupName The group name as {@link String}. + * @param serviceName The service name as {@link String}. + * @return A concatenated key like {@code groupName::serviceName}. + */ + private String buildServiceKey(String groupName, String serviceName) { + return groupName + SEPARATOR + serviceName; + } + + @Override + @Fitable(id = "register-fitables") + public void registerFitables(List fitableMetas, Worker worker, Application application) { + try { + log.debug("Registering fitables. [fitableMetas={}, worker={}, aplication={}]", + fitableMetas, + worker.getId(), + application.getNameVersion()); + for (FitableMeta meta : fitableMetas) { + FitableInfo fitable = meta.getFitable(); + String groupName = this.getGroupName(fitable); + String serviceName = this.getServiceName(fitable); + List instances = createInstance(worker, application, meta); + for (Instance instance : instances) { + this.namingService.registerInstance(serviceName, groupName, instance); + } + } + } catch (NacosException e) { + log.error("Failed to register fitables due to registry error.", e); + } + } + + private String getServiceName(FitableInfo fitable) { + return fitable.getFitableId() + SEPARATOR + fitable.getFitableVersion(); + } + + private String getGroupName(FitableInfo fitable) { + return fitable.getGenericableId() + SEPARATOR + fitable.getGenericableVersion(); + } + + private String getGroupName(GenericableInfo genericable) { + return genericable.getGenericableId() + SEPARATOR + genericable.getGenericableVersion(); + } + + private List createInstance(Worker worker, Application application, FitableMeta meta) { + log.debug("Creating instance for worker. [worker={}, application={}, meta={}]", + worker.getId(), + application.getNameVersion(), + meta); + List instances = new ArrayList<>(); + for (Address address : worker.getAddresses()) { + List endpoints = address.getEndpoints(); + for (Endpoint endpoint : endpoints) { + Instance instance = new Instance(); + instance.setIp(address.getHost()); + instance.setPort(endpoint.getPort()); + HashMap metadata = this.buildInstanceMetadata(worker, application, meta); + instance.setMetadata(metadata); + this.setInstanceProperties(instance); + instances.add(instance); + } + } + return instances; + } + + /** + * Build metadata for service instance, including worker, application and FitableMeta information. + * + * @param worker The worker node object. + * @param application The application object. + * @param meta The {@link FitableMeta} metadata object. + * @return A {@link Map} containing all serialized metadata. + */ + private HashMap buildInstanceMetadata(Worker worker, Application application, FitableMeta meta) { + HashMap metadata = new HashMap<>(); + if (this.nacosConfig.getHeartbeatInterval() != null) { + metadata.put(HEART_BEAT_INTERVAL, String.valueOf(this.nacosConfig.getHeartbeatInterval())); + } + if (this.nacosConfig.getHeartbeatTimeout() != null) { + metadata.put(HEART_BEAT_TIMEOUT, String.valueOf(this.nacosConfig.getHeartbeatTimeout())); + } + try { + metadata.put(WORKER_KEY, this.objectMapper.writeValueAsString(worker)); + metadata.put(APPLICATION_KEY, this.objectMapper.writeValueAsString(application)); + metadata.put(FITABLE_META_KEY, this.objectMapper.writeValueAsString(meta)); + } catch (JsonProcessingException e) { + log.error("Failed to serialize metadata for worker.", e); + } + return metadata; + } + + private void setInstanceProperties(Instance instance) { + if (!this.nacosConfig.getIsEphemeral()) { + instance.setEphemeral(false); + } + if (this.nacosConfig.getWeight() != null) { + instance.setWeight(this.nacosConfig.getWeight()); + } + } + + @Override + @Fitable(id = "unregister-fitables") + public void unregisterFitables(List fitables, String workerId) { + log.debug("Unregistering fitables for worker. [fitables={}, workerId={}]", fitables, workerId); + for (FitableInfo fitable : fitables) { + this.unregisterSingleFitable(fitable, workerId); + } + } + + private void unregisterSingleFitable(FitableInfo fitable, String workerId) { + String groupName = this.getGroupName(fitable); + String serviceName = this.getServiceName(fitable); + try { + List instances = this.namingService.selectInstances(serviceName, groupName, true); + this.unregisterMatchingInstances(instances, workerId, serviceName, groupName); + } catch (NacosException e) { + log.error("Failed to unregister fitable due to registry error.", e); + } + } + + private void unregisterMatchingInstances(List instances, String workerId, String serviceName, + String groupName) { + for (Instance instance : instances) { + try { + Worker worker = this.objectMapper.readValue(instance.getMetadata().get(WORKER_KEY), Worker.class); + if (Objects.equals(workerId, worker.getId())) { + this.namingService.deregisterInstance(serviceName, groupName, instance); + } + } catch (JsonProcessingException e) { + log.error("Failed to parse worker metadata for fitable.", e); + } catch (NacosException e) { + log.error("Failed to deregister instance.", e); + } + } + } + + @Override + @Fitable(id = "query-fitables-addresses") + public List queryFitables(List fitables, String workerId) { + log.debug("Querying fitables for worker. [fitables={}, workerId={}]", fitables, workerId); + Map resultMap = new HashMap<>(); + for (FitableInfo fitable : fitables) { + try { + List instances = this.queryInstances(fitable); + if (instances.isEmpty()) { + continue; + } + this.processApplicationInstances(resultMap, fitable, instances); + } catch (Exception e) { + log.error("Failed to query fitables for genericableId.", e); + } + } + return new ArrayList<>(resultMap.values()); + } + + private void processApplicationInstances(Map resultMap, FitableInfo fitable, + List instances) { + Map> appInstancesMap = groupInstancesByApplication(instances); + for (Map.Entry> entry : appInstancesMap.entrySet()) { + Application application = entry.getKey(); + List appInstances = entry.getValue(); + FitableMeta meta = parseFitableMeta(appInstances.get(0)); + Set workers = extractWorkers(appInstances, application); + FitableAddressInstance fai = resultMap.computeIfAbsent(fitable, k -> { + FitableAddressInstance newFai = new FitableAddressInstance(); + newFai.setFitable(fitable); + newFai.setApplicationInstances(new ArrayList<>()); + return newFai; + }); + ApplicationInstance appInstance = new ApplicationInstance(); + appInstance.setApplication(application); + appInstance.setFormats(meta.getFormats()); + appInstance.setWorkers(new ArrayList<>(workers)); + fai.getApplicationInstances().add(appInstance); + } + } + + /** + * Extract all workers corresponding to instances and adjust addresses based on application extension information. + * + * @param appInstances The list of application instances. + * @param application The application object. + * @return Set of workers. + */ + private Set extractWorkers(List appInstances, Application application) { + Set workers = new HashSet<>(); + for (Instance instance : appInstances) { + Worker worker = parseWorker(instance); + workers.add(worker); + } + if (application.getExtensions().containsKey(CLUSTER_DOMAIN_KEY)) { + this.replaceAddresses(workers, application); + } + return workers; + } + + private Map> groupInstancesByApplication(List instances) { + Map> map = new HashMap<>(); + for (Instance instance : instances) { + Application app = this.parseApplication(instance); + map.computeIfAbsent(app, k -> new ArrayList<>()).add(instance); + } + return map; + } + + private List queryInstances(FitableInfo fitable) throws NacosException { + String groupName = this.getGroupName(fitable); + String serviceName = this.getServiceName(fitable); + return this.namingService.selectInstances(serviceName, groupName, true); + } + + private FitableMeta parseFitableMeta(Instance instance) { + try { + return this.objectMapper.readValue(instance.getMetadata().get(FITABLE_META_KEY), FitableMeta.class); + } catch (JsonProcessingException e) { + log.error("Failed to parse fitable meta for instance.", e); + FitableMeta meta = new FitableMeta(); + meta.setFitable(new FitableInfo()); + return meta; + } + } + + private Application parseApplication(Instance instance) { + try { + return this.objectMapper.readValue(instance.getMetadata().get(APPLICATION_KEY), Application.class); + } catch (JsonProcessingException e) { + log.error("Failed to parse application metadata for instance.", e); + Application app = new Application(); + app.setNameVersion("unknown"); + return app; + } + } + + private Worker parseWorker(Instance instance) { + try { + return this.objectMapper.readValue(instance.getMetadata().get(WORKER_KEY), Worker.class); + } catch (JsonProcessingException e) { + log.error("Failed to parse worker metadata for instance.", e); + Worker worker = new Worker(); + Address address = new Address(); + address.setHost(instance.getIp()); + + Endpoint endpoint = new Endpoint(); + endpoint.setPort(instance.getPort()); + endpoint.setProtocol(1); + + address.setEndpoints(Collections.singletonList(endpoint)); + worker.setAddresses(Collections.singletonList(address)); + return worker; + } + } + + private void replaceAddresses(Set workers, Application application) { + Address address = new Address(); + address.setHost(application.getExtensions().get(CLUSTER_DOMAIN_KEY)); + address.setEndpoints(buildEndPoints(application.getExtensions())); + workers.forEach(w -> w.setAddresses(Collections.singletonList(address))); + } + + private List buildEndPoints(Map extensions) { + List endpoints = new ArrayList<>(); + for (Map.Entry entry : extensions.entrySet()) { + Matcher matcher = CLUSTER_PORT_PATTERN.matcher(entry.getKey()); + if (matcher.matches()) { + String protocolName = matcher.group(1); + CommunicationProtocol protocol = CommunicationProtocol.valueOf(StringUtils.toUpperCase(protocolName)); + Endpoint endpoint = new Endpoint(); + endpoint.setPort(Integer.valueOf(entry.getValue())); + endpoint.setProtocol(protocol.code()); + endpoints.add(endpoint); + } + } + return endpoints; + } + + @Override + @Fitable(id = "subscribe-fitables") + public List subscribeFitables(List fitables, String workerId, + String callbackFitableId) { + log.debug("Subscribing to fitables for worker. [fitables={}, workerId={}, callbackFitableId={}]", + fitables, + workerId, + callbackFitableId); + for (FitableInfo fitable : fitables) { + try { + String groupName = this.getGroupName(fitable); + String serviceName = this.getServiceName(fitable); + if (this.serviceSubscriptions.containsKey(buildServiceKey(groupName, serviceName))) { + log.debug("Already subscribed to service. [groupName={}, serviceName={}]", groupName, serviceName); + continue; + } + EventListener eventListener = + this.serviceSubscriptions.computeIfAbsent(buildServiceKey(groupName, serviceName), + k -> event -> { + if (event instanceof NamingEvent || event instanceof NamingChangeEvent) { + onServiceChanged(fitable); + } + }); + this.namingService.subscribe(serviceName, groupName, eventListener); + } catch (NacosException e) { + log.error("Failed to subscribe to Nacos service.", e); + } + } + return this.queryFitables(fitables, workerId); + } + + @Override + @Fitable(id = "unsubscribe-fitables") + public void unsubscribeFitables(List fitables, String workerId, String callbackFitableId) { + log.debug("Unsubscribing from fitables for worker. [fitables={}, workerId={}, callbackFitableId={}]", + fitables, + workerId, + callbackFitableId); + for (FitableInfo fitable : fitables) { + try { + String groupName = this.getGroupName(fitable); + String serviceName = this.getServiceName(fitable); + EventListener listener = this.serviceSubscriptions.get(buildServiceKey(groupName, serviceName)); + this.namingService.unsubscribe(serviceName, groupName, listener); + this.serviceSubscriptions.remove(buildServiceKey(groupName, serviceName)); + } catch (NacosException e) { + log.error("Failed to unsubscribe from Nacos service.", e); + } + } + } + + /** + * Handle service change events, query and notify updates to Fitables instance information. + * + * @param fitableInfo The changed Fitables information. + */ + private void onServiceChanged(FitableInfo fitableInfo) { + List fitableAddressInstances = + this.queryFitables(Collections.singletonList(fitableInfo), this.worker.id()); + this.notify.notifyFitables(fitableAddressInstances); + } + + @Override + @Fitable(id = "query-running-fitables") + public List queryFitableMetas(List genericables) { + log.debug("Querying fitable metas for genericables. [genericables={}]", genericables); + Map> metaEnvironments = new HashMap<>(); + + for (GenericableInfo genericable : genericables) { + this.processGenericableServices(genericable, metaEnvironments); + } + + return this.buildFitableMetaInstances(metaEnvironments); + } + + private void processGenericableServices(GenericableInfo genericable, + Map> metaEnvironments) { + String groupName = this.getGroupName(genericable); + try { + ListView services = this.namingService.getServicesOfServer(1, Integer.MAX_VALUE, groupName); + for (String serviceName : services.getData()) { + this.processServiceInstances(serviceName, groupName, metaEnvironments); + } + } catch (NacosException e) { + log.error("Failed to query fitable metas.", e); + } + } + + private void processServiceInstances(String serviceName, String groupName, + Map> metaEnvironments) { + try { + List instances = this.namingService.selectInstances(serviceName, groupName, true); + if (instances.isEmpty()) { + return; + } + FitableMeta meta = parseFitableMeta(instances.get(0)); + this.collectEnvironmentsFromInstances(instances, meta, metaEnvironments); + } catch (NacosException e) { + log.error("Failed to select instances for service: " + serviceName, e); + } + } + + private void collectEnvironmentsFromInstances(List instances, FitableMeta meta, + Map> metaEnvironments) { + for (Instance instance : instances) { + try { + Worker worker = this.objectMapper.readValue(instance.getMetadata().get(WORKER_KEY), Worker.class); + metaEnvironments.computeIfAbsent(meta, k -> new HashSet<>()).add(worker.getEnvironment()); + } catch (JsonProcessingException e) { + log.error("Failed to parse worker metadata.", e); + } + } + } + + private List buildFitableMetaInstances(Map> metaEnvironments) { + List results = new ArrayList<>(); + for (Map.Entry> entry : metaEnvironments.entrySet()) { + FitableMetaInstance instance = new FitableMetaInstance(); + instance.setMeta(entry.getKey()); + instance.setEnvironments(new ArrayList<>(entry.getValue())); + results.add(instance); + } + return results; + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/resources/application.yml b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/resources/application.yml new file mode 100644 index 00000000..211ee7d8 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-nacos/src/main/resources/application.yml @@ -0,0 +1,11 @@ +fit: + beans: + packages: + - 'modelengine.fit.service' + - 'modelengine.fit.heartbeat' + +matata: + registry: + nacos: + weight: 1 + isEphemeral: true \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-simple/src/main/java/modelengine/fit/heartbeat/server/HeartbeatServer.java b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-simple/src/main/java/modelengine/fit/heartbeat/server/HeartbeatServer.java index ca179f20..6730083e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-simple/src/main/java/modelengine/fit/heartbeat/server/HeartbeatServer.java +++ b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-simple/src/main/java/modelengine/fit/heartbeat/server/HeartbeatServer.java @@ -34,7 +34,7 @@ public HeartbeatServer(WorkerCache cache) { } @Override - @Fitable(id = "DBC9E2F7C0E443F1AC986BBC3D58C27B") + @Fitable(id = "send-heartbeat") public Boolean sendHeartbeat(List beatInfos, Address address) { if (address == null || StringUtils.isBlank(address.getId())) { return false; diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-simple/src/main/java/modelengine/fit/service/server/RegistryServer.java b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-simple/src/main/java/modelengine/fit/service/server/RegistryServer.java index d2841d82..14baeaee 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-service-coordination-simple/src/main/java/modelengine/fit/service/server/RegistryServer.java +++ b/framework/fit/java/fit-builtin/plugins/fit-service-coordination-simple/src/main/java/modelengine/fit/service/server/RegistryServer.java @@ -88,7 +88,7 @@ public Map> getApplicationMetas() { } @Override - @Fitable(id = "dedaa28cfb2742819a9b0271bc34f72a") + @Fitable(id = "register-fitables") public void registerFitables(List fitableMetas, Worker worker, Application application) { if (!this.workers.containsKey(worker.getId()) && this.workers.size() >= MAX_WORKER_NUM) { throw new IllegalStateException("Too many workers."); @@ -121,10 +121,11 @@ private int getActualExpire(Worker worker) { } @Override + @Fitable(id = "unregister-fitables") public void unregisterFitables(List fitables, String workerId) {} @Override - @Fitable(id = "5807f06a3a704708b264ea3c6cfbbd53") + @Fitable(id = "query-fitables-addresses") public List queryFitables(List fitables, String workerId) { List instances = new ArrayList<>(); for (Map.Entry> entry : this.applicationMetas.entrySet()) { @@ -203,17 +204,18 @@ private boolean isMetaInFitables(FitableMeta meta, List fitables) { } @Override - @Fitable(id = "ee0a8337d3654a22a548d5d5abe1d5f3") + @Fitable(id = "subscribe-fitables") public List subscribeFitables(List fitables, String workerId, String callbackFitableId) { return this.queryFitables(fitables, workerId); } @Override + @Fitable(id = "unsubscribe-fitables") public void unsubscribeFitables(List fitables, String workerId, String callbackFitableId) {} @Override - @Fitable(id = "33b1f9b8f1cc49d19719a6536c96e854") + @Fitable(id = "query-running-fitables") public List queryFitableMetas(List genericables) { Map instances = new HashMap<>(); for (Map.Entry> entry : this.applicationMetas.entrySet()) { diff --git a/framework/fit/java/fit-builtin/plugins/fit-service-discovery/src/main/java/modelengine/fit/service/RegistryListener.java b/framework/fit/java/fit-builtin/plugins/fit-service-discovery/src/main/java/modelengine/fit/service/RegistryListener.java index 5760bbdb..4d032087 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-service-discovery/src/main/java/modelengine/fit/service/RegistryListener.java +++ b/framework/fit/java/fit-builtin/plugins/fit-service-discovery/src/main/java/modelengine/fit/service/RegistryListener.java @@ -96,9 +96,9 @@ * @since 2020-08-19 */ @Component -public class RegistryListener implements Registry { +public class RegistryListener implements Registry, Notify { private static final Logger log = Logger.get(RegistryListener.class); - private static final String NOTIFY_FITABLE_ID = "347fd33f3cde4aa891614a9e244ae5e8"; + private static final String NOTIFY_FITABLE_ID = "notify-fitables"; private static final long INITIAL_DELAY = 10L; private static final int BATCH_NUM = 10; private static final Pattern CLUSTER_PORT_PATTERN = Pattern.compile("cluster\\.(.*?)\\.port"); @@ -471,7 +471,8 @@ private void unsubscribe(List fitables) { * @param fitableInstances 表示本地监听的服务地址的更新列表的 {@link List}{@code <}{@link FitableAddressInstance} * {@code >}。 */ - @Fitable(genericable = "b69df5e8cbcd4166aa5029602e7a58cf", id = NOTIFY_FITABLE_ID) + @Override + @Fitable(NOTIFY_FITABLE_ID) public void notifyFitables(List fitableInstances) { if (CollectionUtils.isEmpty(fitableInstances)) { log.info("Received latest fitable instances, but ignored: no data."); diff --git a/framework/fit/java/fit-builtin/plugins/pom.xml b/framework/fit/java/fit-builtin/plugins/pom.xml index d8883496..b4e52efd 100644 --- a/framework/fit/java/fit-builtin/plugins/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/pom.xml @@ -19,6 +19,7 @@ 1.18.36 + 3.0.1 @@ -38,6 +39,7 @@ fit-server-http fit-service-coordination-locator fit-service-coordination-simple + fit-service-coordination-nacos fit-service-discovery fit-service-registry fit-value-fastjson @@ -50,6 +52,11 @@ lombok ${lombok.version} + + com.alibaba.nacos + nacos-client + ${nacos.version} + diff --git a/framework/fit/java/fit-builtin/services/fit-heartbeat/definition/src/main/java/modelengine/fit/heartbeat/HeartbeatService.java b/framework/fit/java/fit-builtin/services/fit-heartbeat/definition/src/main/java/modelengine/fit/heartbeat/HeartbeatService.java index fc8a04ce..e8fea6cc 100644 --- a/framework/fit/java/fit-builtin/services/fit-heartbeat/definition/src/main/java/modelengine/fit/heartbeat/HeartbeatService.java +++ b/framework/fit/java/fit-builtin/services/fit-heartbeat/definition/src/main/java/modelengine/fit/heartbeat/HeartbeatService.java @@ -24,7 +24,7 @@ public interface HeartbeatService { * @param address 表示本地地址的 {@link Address}。 * @return 表示发送结果的 {@link Boolean}。 */ - @Genericable(id = "e12fd1c57fd84f50a673d93d13074082") + @Genericable(id = "modelengine.fit.heartbeat.send-heartbeat") Boolean sendHeartbeat(List heartbeatInfo, Address address); /** @@ -34,7 +34,7 @@ public interface HeartbeatService { * @param address 表示本地地址的 {@link Address}。 * @return 表示发送结果的 {@link Boolean}。 */ - @Genericable(id = "67e6370725df427ebab9a6a6f1ada60c") + @Genericable(id = "modelengine.fit.heartbeat.stop-heartbeat") Boolean stopHeartbeat(List heartbeatInfo, Address address); /** diff --git a/framework/fit/java/fit-builtin/services/fit-service/definition/src/main/java/modelengine/fit/service/Notify.java b/framework/fit/java/fit-builtin/services/fit-service/definition/src/main/java/modelengine/fit/service/Notify.java new file mode 100644 index 00000000..d4fbfcbf --- /dev/null +++ b/framework/fit/java/fit-builtin/services/fit-service/definition/src/main/java/modelengine/fit/service/Notify.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.service; + +import modelengine.fit.service.entity.FitableAddressInstance; +import modelengine.fitframework.annotation.Genericable; + +import java.util.List; + +/** + * Represents notification service for updating Fitables instance information. + * + * @author 董智豪 + * @since 2025-06-20 + */ +public interface Notify { + /** + * Notify to update Fitables instances. + * + * @param fitableInstances A {@link List}{@code <}{@link FitableAddressInstance}{@code >} representing all instance + * information for specified service implementations. + */ + @Genericable(id = "modelengine.fit.service.registry-listener.notify-fitables") + void notifyFitables(List fitableInstances); +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/services/fit-service/definition/src/main/java/modelengine/fit/service/RegistryService.java b/framework/fit/java/fit-builtin/services/fit-service/definition/src/main/java/modelengine/fit/service/RegistryService.java index 1b2c4a60..c6d1d15a 100644 --- a/framework/fit/java/fit-builtin/services/fit-service/definition/src/main/java/modelengine/fit/service/RegistryService.java +++ b/framework/fit/java/fit-builtin/services/fit-service/definition/src/main/java/modelengine/fit/service/RegistryService.java @@ -31,7 +31,7 @@ public interface RegistryService { * @param worker 表示服务实现所在的进程信息的 {@link Worker}。 * @param application 表示服务实现所在的应用信息的 {@link Application}。 */ - @Genericable(id = "85bdce64cf724589b87cb6b6a950999d") + @Genericable(id = "modelengine.fit.registry.registry-service.register-fitables") void registerFitables(List fitableMetas, Worker worker, Application application); /** @@ -40,7 +40,7 @@ public interface RegistryService { * @param fitables 表示待取消注册的服务实现列表的 {@link List}{@code <}{@link FitableInfo}{@code >}。 * @param workerId 表示服务实现所在的进程的唯一标识的 {@link String}。 */ - @Genericable(id = "c02af9dafb5b4a609f8c586a8e884710") + @Genericable(id = "modelengine.fit.registry.registry-service.unregister-fitables") void unregisterFitables(List fitables, String workerId); /** @@ -50,7 +50,7 @@ public interface RegistryService { * @param workerId 表示指定的进程的唯一标识的 {@link String}。 * @return 表示指定服务实现的所有实例信息的 {@link List}{@code <}{@link FitableAddressInstance}{@code >}。 */ - @Genericable(id = "33be4142494e4742aa122555a451d996") + @Genericable(id = "modelengine.fit.registry.registry-service.query-fitables-addresses") List queryFitables(List fitables, String workerId); /** @@ -61,7 +61,7 @@ public interface RegistryService { * @param callbackFitableId 表示订阅回调服务实现的唯一标识的 {@link String}。 * @return 表示指定服务实现的所有实例信息的 {@link List}{@code <}{@link FitableAddressInstance}{@code >}。 */ - @Genericable(id = "c9aa580f3fa845c99c2c6145a0499e45") + @Genericable(id = "modelengine.fit.registry.registry-service.subscribe-fitables") List subscribeFitables(List fitables, String workerId, String callbackFitableId); @@ -72,7 +72,7 @@ List subscribeFitables(List fitables, Strin * @param workerId 表示指定的进程的唯一标识的 {@link String}。 * @param callbackFitableId 表示取消订阅回调服务实现的唯一标识的 {@link String}。 */ - @Genericable(id = "087994fc907b4f76b9f9b2a62e07ef2c") + @Genericable(id = "modelengine.fit.registry.registry-service.unsubscribe-fitables") void unsubscribeFitables(List fitables, String workerId, String callbackFitableId); /** @@ -81,6 +81,6 @@ List subscribeFitables(List fitables, Strin * @param genericables 表示指定服务列表的 {@link List}{@code <}{@link GenericableInfo}{@code >}。 * @return 表示正在运行的服务实现元数据列表的 {@link List}{@code <}{@link FitableMetaInstance}{@code >}。 */ - @Genericable(id = "7c52fb4fdfa243af928f23607fbbee02") + @Genericable(id = "modelengine.fit.registry.registry-service.query-running-fitables") List queryFitableMetas(List genericables); } diff --git a/framework/fit/java/fit-conf/fit-conf/src/main/java/modelengine/fitframework/conf/runtime/DefaultRegistry.java b/framework/fit/java/fit-conf/fit-conf/src/main/java/modelengine/fitframework/conf/runtime/DefaultRegistry.java index 3cc2ff0f..be283b43 100644 --- a/framework/fit/java/fit-conf/fit-conf/src/main/java/modelengine/fitframework/conf/runtime/DefaultRegistry.java +++ b/framework/fit/java/fit-conf/fit-conf/src/main/java/modelengine/fitframework/conf/runtime/DefaultRegistry.java @@ -31,6 +31,7 @@ public class DefaultRegistry implements Registry { private List authRequiredServices; private Map extensions; private DefaultSecureAccess secureAccess; + private String mode = RegistryConnectMode.DIRECT.name(); /** * 设置主机地址的配置。 @@ -106,11 +107,25 @@ public void setExtensions(Map extensions) { this.extensions = extensions; } + /** + * 设置注册中心连接模式。 + * + * @param mode 表示待设置的模式配置的 {@link String}。 + */ + public void setMode(String mode) { + this.mode = mode; + } + @Override public String host() { return this.host; } + @Override + public RegistryConnectMode mode() { + return RegistryConnectMode.fromMode(this.mode); + } + @Override public int port() { return this.port; @@ -184,4 +199,4 @@ public String toString() { this.extensions, this.secureAccess); } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-runtime/src/main/resources/fitframework.yml b/framework/fit/java/fit-runtime/src/main/resources/fitframework.yml index 37c9444d..e735382e 100644 --- a/framework/fit/java/fit-runtime/src/main/resources/fitframework.yml +++ b/framework/fit/java/fit-runtime/src/main/resources/fitframework.yml @@ -1,105 +1,102 @@ application: - name: 'application' # 默认应用名 + name: "application" # 默认应用名 worker: - id: 'default-worker-id' # 默认的进程唯一标识,该配置需要进行覆盖,避免workerId相同注册服务混乱 - host: 'localhost' # 该配置需要修改为真实启动的本地ip地址 - environment: 'local' # 默认环境标 - environment-sequence: 'local' # 默认环境调用链 + id: "default-worker-id" # 默认的进程唯一标识,该配置需要进行覆盖,避免workerId相同注册服务混乱 + host: "localhost" # 该配置需要修改为真实启动的本地ip地址 + environment: "local" # 默认环境标 + environment-sequence: "local" # 默认环境调用链 exit: graceful: true matata: registry: - host: 'localhost' # 默认连接的注册中心为本地 - port: 8080 # 默认连接注册中心的端口为本地默认的 8080 端口 - protocol: 2 # 注册中心默认使用 Http 的传输协议 - environment: 'local' # 默认注册中心的环境标和本地默认配置一致 + environment: "local" # 默认注册中心的环境标和本地默认配置一致 available-services: # 将注册中心和获取地址相关的服务进行配置,其他服务都可以通过以下服务进行地址获取 - # 订阅服务并获取所订阅服务地址的接口 - - genericable-name: 'modelengine.fit.registry.RegistryService.subscribeFitables' - genericable-id: 'c9aa580f3fa845c99c2c6145a0499e45' - genericable-version: '1.0.0' - fitable-id: 'ee0a8337d3654a22a548d5d5abe1d5f3' - fitable-version: '1.0.0' - formats: - - 1 - # 直接获取服务地址的接口 - - genericable-name: 'modelengine.fit.registry.RegistryService.queryFitablesAddresses' - genericable-id: '33be4142494e4742aa122555a451d996' - genericable-version: '1.0.0' - fitable-id: '5807f06a3a704708b264ea3c6cfbbd53' - fitable-version: '1.0.0' - formats: - - 1 - # 查询注册中心正在运行的服务实现信息的接口 - - genericable-name: 'modelengine.fit.registry.RegistryService.queryRunningFitables' - genericable-id: '7c52fb4fdfa243af928f23607fbbee02' - genericable-version: '1.0.0' - fitable-id: '33b1f9b8f1cc49d19719a6536c96e854' - fitable-version: '1.0.0' - formats: - - 1 - # 向注册中心申请令牌的接口 - - genericable-name: 'modelengine.fit.registry.TokenService.applyToken' - genericable-id: 'matata.registry.secure-access.apply-token' - genericable-version: '1.0.0' - fitable-id: 'apply_token' - fitable-version: '1.0.0' - formats: - - 1 - # 向注册中心刷新令牌的接口 - - genericable-name: 'modelengine.fit.registry.TokenService.refreshToken' - genericable-id: 'matata.registry.secure-access.refresh-token' - genericable-version: '1.0.0' - fitable-id: 'refresh_token_for_registry_server' - fitable-version: '1.0.0' - formats: - - 1 - # 向注册中心发送心跳 - - genericable-name: 'modelengine.fit.heartbeat.sendHeartbeat' - genericable-id: 'e12fd1c57fd84f50a673d93d13074082' - genericable-version: '1.0.0' - fitable-id: 'DBC9E2F7C0E443F1AC986BBC3D58C27B' - fitable-version: '1.0.0' - formats: - - 1 - # 向注册中心注册服务信息 - - genericable-name: 'modelengine.fit.registry.RegistryService.registerFitables' - genericable-id: '85bdce64cf724589b87cb6b6a950999d' - genericable-version: '1.0.0' - fitable-id: 'dedaa28cfb2742819a9b0271bc34f72a' - fitable-version: '1.0.0' - formats: - - 1 + # 订阅服务并获取所订阅服务地址的接口 + - genericable-name: "modelengine.fit.registry.RegistryService.subscribeFitables" + genericable-id: "modelengine.fit.registry.registry-service.subscribe-fitables" + genericable-version: "1.0.0" + fitable-id: "subscribe-fitables" + fitable-version: "1.0.0" + formats: + - 1 + # 直接获取服务地址的接口 + - genericable-name: "modelengine.fit.registry.RegistryService.queryFitablesAddresses" + genericable-id: "modelengine.fit.registry.registry-service.query-fitables-addresses" + genericable-version: "1.0.0" + fitable-id: "query-fitables-addresses" + fitable-version: "1.0.0" + formats: + - 1 + # 查询注册中心正在运行的服务实现信息的接口 + - genericable-name: "modelengine.fit.registry.RegistryService.queryRunningFitables" + genericable-id: "modelengine.fit.registry.registry-service.query-running-fitables" + genericable-version: "1.0.0" + fitable-id: "query-running-fitables" + fitable-version: "1.0.0" + formats: + - 1 + # 向注册中心申请令牌的接口 + - genericable-name: "modelengine.fit.registry.TokenService.applyToken" + genericable-id: "matata.registry.secure-access.apply-token" + genericable-version: "1.0.0" + fitable-id: "apply-token" + fitable-version: "1.0.0" + formats: + - 1 + # 向注册中心刷新令牌的接口 + - genericable-name: "modelengine.fit.registry.TokenService.refreshToken" + genericable-id: "matata.registry.secure-access.refresh-token" + genericable-version: "1.0.0" + fitable-id: "refresh-token-for-registry-server" + fitable-version: "1.0.0" + formats: + - 1 + # 向注册中心发送心跳 + - genericable-name: "modelengine.fit.heartbeat.sendHeartbeat" + genericable-id: "modelengine.fit.heartbeat.send-heartbeat" + genericable-version: "1.0.0" + fitable-id: "send-heartbeat" + fitable-version: "1.0.0" + formats: + - 1 + # 向注册中心注册服务信息 + - genericable-name: "modelengine.fit.registry.RegistryService.registerFitables" + genericable-id: "modelengine.fit.registry.registry-service.register-fitables" + genericable-version: "1.0.0" + fitable-id: "register-fitables" + fitable-version: "1.0.0" + formats: + - 1 auth-required-services: # 将注册中心和心跳相关的服务进行配置,表示其需要认证鉴权 - # 订阅服务并获取所订阅服务地址的接口 - - genericable-name: 'modelengine.fit.registry.RegistryService.subscribeFitables' - genericable-id: 'c9aa580f3fa845c99c2c6145a0499e45' - # 直接获取服务地址的接口 - - genericable-name: 'modelengine.fit.registry.RegistryService.queryFitablesAddresses' - genericable-id: '33be4142494e4742aa122555a451d996' - # 查询注册中心正在运行的服务实现信息的接口 - - genericable-name: 'modelengine.fit.registry.RegistryService.queryRunningFitables' - genericable-id: '7c52fb4fdfa243af928f23607fbbee02' - # 向注册中心服务端注册服务实现列表 - - genericable-name: 'modelengine.fit.registry.RegistryService.registerFitables' - genericable-id: '85bdce64cf724589b87cb6b6a950999d' - # 向注册中心服务端取消注册服务实现列表 - - genericable-name: 'modelengine.fit.registry.RegistryService.unregisterFitables' - genericable-id: 'c02af9dafb5b4a609f8c586a8e884710' - # 向注册中心服务端取消订阅指定服务实现的实例信息 - - genericable-name: 'modelengine.fit.registry.RegistryService.unsubscribeFitables' - genericable-id: '087994fc907b4f76b9f9b2a62e07ef2c' - # 发送心跳信息 - - genericable-name: 'modelengine.fit.heartbeat.sendHeartbeat' - genericable-id: 'e12fd1c57fd84f50a673d93d13074082' - # 发送停止心跳信息 - - genericable-name: 'modelengine.fit.heartbeat.stopHeartbeat' - genericable-id: '67e6370725df427ebab9a6a6f1ada60c' + # 订阅服务并获取所订阅服务地址的接口 + - genericable-name: "modelengine.fit.registry.RegistryService.subscribeFitables" + genericable-id: "modelengine.fit.registry.registry-service.subscribe-fitables" + # 直接获取服务地址的接口 + - genericable-name: "modelengine.fit.registry.RegistryService.queryFitablesAddresses" + genericable-id: "modelengine.fit.registry.registry-service.query-fitables-addresses" + # 查询注册中心正在运行的服务实现信息的接口 + - genericable-name: "modelengine.fit.registry.RegistryService.queryRunningFitables" + genericable-id: "modelengine.fit.registry.registry-service.query-running-fitables" + # 向注册中心服务端注册服务实现列表 + - genericable-name: "modelengine.fit.registry.RegistryService.registerFitables" + genericable-id: "modelengine.fit.registry.registry-service.register-fitables" + # 向注册中心服务端取消注册服务实现列表 + - genericable-name: "modelengine.fit.registry.RegistryService.unregisterFitables" + genericable-id: "modelengine.fit.registry.registry-service.unregister-fitables" + # 向注册中心服务端取消订阅指定服务实现的实例信息 + - genericable-name: "modelengine.fit.registry.RegistryService.unsubscribeFitables" + genericable-id: "modelengine.fit.registry.registry-service.unsubscribe-fitables" + # 发送心跳信息 + - genericable-name: "modelengine.fit.heartbeat.sendHeartbeat" + genericable-id: "modelengine.fit.heartbeat.send-heartbeat" + # 发送停止心跳信息 + - genericable-name: "modelengine.fit.heartbeat.stopHeartbeat" + genericable-id: "modelengine.fit.heartbeat.stop-heartbeat" fit: beans: packages: - - 'modelengine.fitframework' - - 'modelengine.fit' \ No newline at end of file + - "modelengine.fitframework" + - "modelengine.fit" diff --git a/framework/fit/python/conf/fit.yml b/framework/fit/python/conf/fit.yml index c4329f69..51f86858 100644 --- a/framework/fit/python/conf/fit.yml +++ b/framework/fit/python/conf/fit.yml @@ -1,502 +1,502 @@ fit.public.genericables.9289a2a4322d47d38f33fc32c47f04d2: - name: 'StartServer' + name: "StartServer" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: 911533a440e541a2900da06e01d3e6de: aliases: - - 'fit.http.server.py' + - "fit.http.server.py" 8f1e46e8a25a4ed391cb115b766d76db: aliases: - - 'fit.grpc.server.py' + - "fit.grpc.server.py" FIT_SERVER_START_UC_FITABLE_ID: aliases: - - 'fit.uc.server.py' + - "fit.uc.server.py" fit.public.genericables.d45f8ecbfb9c4d11a38143233c878a8f: tags: - - 'localOnly' + - "localOnly" fitables: 913d6d1c47ed4c4481dd84a5b667a1ef: 2fb08101aa94495face6aeef49cdc98a: fit.public.genericables.1b9bfc4a2b2141d5b31aa06791d645b4: - name: 'StopServer' + name: "StopServer" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: 2f661c07515f43cf802e30f7d81efbae: aliases: - - 'fit.http.server.py' + - "fit.http.server.py" 0970e120501047fa800078edd7437fa4: aliases: - - 'fit.grpc.server.py' + - "fit.grpc.server.py" FIT_SERVER_STOP_UC_FITABLE_ID: aliases: - - 'fit.uc.server.py' + - "fit.uc.server.py" fit.public.genericables.8f69322009a8411ca7df1e3a67a856e5: - name: 'GetServerAddress' + name: "GetServerAddress" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: FIT_SERVER_GET_ADDRESS_HTTP_FITABLE_ID: aliases: - - 'fit.http.server.py' + - "fit.http.server.py" FIT_SERVER_GET_ADDRESS_GRPC_FITABLE_ID: aliases: - - 'fit.grpc.server.py' + - "fit.grpc.server.py" FIT_SERVER_GET_ADDRESS_UC_FITABLE_ID: aliases: - - 'fit.uc.server.py' + - "fit.uc.server.py" fit.public.genericables.9046fe29c2a947448d86bf8178c745e1: - name: 'load-balancer' + name: "load-balancer" route: - default: 'c5fcfc2cd8b54fa6940ad8ef67f257b4' + default: "c5fcfc2cd8b54fa6940ad8ef67f257b4" tags: - - 'nonTraceable' + - "nonTraceable" fitables: c5fcfc2cd8b54fa6940ad8ef67f257b4: aliases: - - 'python_default_lb' + - "python_default_lb" fit.public.genericables.d58a444c9cd546b5b284353c0326209c: - name: 'load-balance-filter' + name: "load-balance-filter" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: '8a67f9e84e7e4077897a9b615c067dd4' + default: "8a67f9e84e7e4077897a9b615c067dd4" fitables: 8a67f9e84e7e4077897a9b615c067dd4: aliases: - - 'lb_filter_python_impl' + - "lb_filter_python_impl" fit.public.genericables.093325db3dfa4b42872512d91e865ccb: - name: 'config-subscribeConfiguration' + name: "config-subscribeConfiguration" tags: - - 'nonTraceable' + - "nonTraceable" fitables: 753f1399a2754d1ea6c749e41c25bfd0: aliases: - - 'default' + - "default" fit.public.genericables.2514453162a4498791b59e7e299b36d1: - name: 'config-unsubscribeConfiguration' + name: "config-unsubscribeConfiguration" tags: - - 'nonTraceable' + - "nonTraceable" fitables: 9cf969d1e56d48e2a15435750b6358d2: aliases: - - 'default' + - "default" fit.public.genericables.4c0e733d04e94f488c122925052aceb1: # 测试环境下,需使用生产配置;实际生产环境下不需要 - name: 'config-download' + name: "config-download" tags: - - 'nonTraceable' + - "nonTraceable" fitables: ef327ef3a9a040bcb223311a70959872: aliases: - - 'default' + - "default" fit.public.genericables.ae024f34dd7a4dc88e19a1a8cf801f29: - name: 'server-config-upload' + name: "server-config-upload" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: '2ae9d88f46894f7bb0fcd45cf544cb52' + default: "2ae9d88f46894f7bb0fcd45cf544cb52" fit.public.genericables.887837e5d33f4fdfa76b05c75458fa0c: - name: 'request_response' + name: "request_response" route: - dynamic: 'b0d8a8e116a34f1b8e45ce2be8dde6b9' + dynamic: "b0d8a8e116a34f1b8e45ce2be8dde6b9" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.bf2e1029e8844fe9afb698affb95d39c: - name: 'heart-beat-online' + name: "heart-beat-online" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: 6bd00d54d5684a0480cb567a058210f7: aliases: - - 'heart_beat_online_fit_python' + - "heart_beat_online_fit_python" CM_ONLINE_HEART_BEAT_FIT_ID: aliases: - - 'heart_beat_online_om_python' + - "heart_beat_online_om_python" fit.public.genericables.HEART_BEAT_EXIT_UNEXPECTEDLY_GEN_ID: - name: 'heart-beat-exit-unexpectedly' + name: "heart-beat-exit-unexpectedly" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" route: - default: 'HEART_BEAT_EXIT_UNEXPECTEDLY_FIT_ID' + default: "HEART_BEAT_EXIT_UNEXPECTEDLY_FIT_ID" fit.public.genericables.18e47e184fd44c70af63eec3227bee2e: - name: 'heart-beat-offline' + name: "heart-beat-offline" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: 4e01a11d760a4614b431f760ee7f51ac: aliases: - - 'heart_beat_offline_python' + - "heart_beat_offline_python" fit.public.genericables.564286f7db6349b2b29db49feac3b7da: - name: 'get_fit_service_address_list' + name: "get_fit_service_address_list" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: 9602150ac5694585ab9a9e3d7561f48b: aliases: - - 'get_service_address_list_python' + - "get_service_address_list_python" fit.public.genericables.2ac926e6e40245b78b7bdda23bcb727b: - name: 'online_fit_services' + name: "online_fit_services" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: ONLINE_FIT_SERVICE_FITABLE_ID: aliases: - - 'online_fit_services_python' + - "online_fit_services_python" route: - default: 'ONLINE_FIT_SERVICE_FITABLE_ID' -fit.public.genericables.7c52fb4fdfa243af928f23607fbbee02: - name: 'QUERY_FITABLE_METAS_GEN_ID' + default: "ONLINE_FIT_SERVICE_FITABLE_ID" +fit.public.genericables.modelengine.fit.registry.registry-service.query-running-fitables: + name: "QUERY_FITABLE_METAS_GEN_ID" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: '33b1f9b8f1cc49d19719a6536c96e854' + default: "query-running-fitables" fit.public.genericables.GET_FITABLES_OF_GENERICABLE_GEN_ID: - name: 'get_fitables_of_genericable' + name: "get_fitables_of_genericable" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" route: - default: 'GET_FITABLES_OF_GENERICABLE_FIT_ID' + default: "GET_FITABLES_OF_GENERICABLE_FIT_ID" fit.public.genericables.8b7f3c01ec4f4a5aa6a291e82587e946: - name: 'offline_fit_service' + name: "offline_fit_service" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: d4b42ada0f744441a8b1eca9f2919a8a: aliases: - - 'offline_fit_service_python' + - "offline_fit_service_python" fit.public.genericables.49612be00e38424cac2e8ea812936cb4: - name: 'get_registry_address' + name: "get_registry_address" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: e482bcfaded042be87873bb63884bc14: aliases: - - 'get_registry_address_fit_python' + - "get_registry_address_fit_python" route: - default: 'e482bcfaded042be87873bb63884bc14' + default: "e482bcfaded042be87873bb63884bc14" fit.public.genericables.e5f5a8809c534d21a6639e0e1ae2ccae: - name: 'set_fitable_instance_status' + name: "set_fitable_instance_status" fitables: 711de8c45e3d498b885801b5bc7394ad: aliases: - - 'set_fitable_status_python' + - "set_fitable_status_python" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.0e166105f93c46a49966ba774d9ec10a: - name: 'remove_fit_listener' + name: "remove_fit_listener" fitables: af0d9d541ac94da7a8d28cfd465107f5: aliases: - - 'remove_fit_listener_python' + - "remove_fit_listener_python" tags: - - 'localOnly' - - 'nonTraceable' -fit.public.genericables.c9aa580f3fa845c99c2c6145a0499e45: - name: 'registry_server_subscribe' + - "localOnly" + - "nonTraceable" +fit.public.genericables.modelengine.fit.registry.registry-service.subscribe-fitables: + name: "registry_server_subscribe" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: 'ee0a8337d3654a22a548d5d5abe1d5f3' -fit.public.genericables.33be4142494e4742aa122555a451d996: - name: 'query_fitable_addresses' + default: "subscribe-fitables" +fit.public.genericables.modelengine.fit.registry.registry-service.query-fitables-addresses: + name: "query_fitable_addresses" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: '5807f06a3a704708b264ea3c6cfbbd53' + default: "query-fitables-addresses" fit.public.genericables.2d47d38f33fc32c47f049289a2a432d2: - name: 'dynamic_loading_start' + name: "dynamic_loading_start" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: '6e01d3e6911533a440e541a2900da0de' + default: "6e01d3e6911533a440e541a2900da0de" fit.public.genericables.fd059427d2b742f590533ea95391144a: - name: 'configuration_server_append' + name: "configuration_server_append" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: '0c3217aa311a405e8a7cff40e9fee60a' + default: "0c3217aa311a405e8a7cff40e9fee60a" fitables: 0c3217aa311a405e8a7cff40e9fee60a: aliases: - - 'default' + - "default" fit.public.genericables.01c48f78a6964f4392d026df694b33e5: - name: 'configuration_server_remove' + name: "configuration_server_remove" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: '87736d2ff21d4e57923bd1760e1bca3f' + default: "87736d2ff21d4e57923bd1760e1bca3f" fitables: 87736d2ff21d4e57923bd1760e1bca3f: aliases: - - 'default' + - "default" fit.public.genericables.d166effd0ef842fe85b8133d02568057: - name: 'configuration_agent_unsubscribe' + name: "configuration_agent_unsubscribe" route: - default: 'unsubscribe' + default: "unsubscribe" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.918fbf55d64b4de8910d08cfcb41d31c: - name: 'configuration_agent_download' + name: "configuration_agent_download" fitables: ef64c99ddeeb48259e10828bc62c211f: aliases: - - 'py_impl' + - "py_impl" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.90c52daf8cc14e22ad8cfb9a19d21157: - name: 'configuration_agent_upload' + name: "configuration_agent_upload" fitables: CONFIGURATION_AGENT_UPLOAD_FIT_ID: aliases: - - 'python_configuration_upload' + - "python_configuration_upload" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.63ee92ae39c54ee7a529460e29aee542: - name: 'server_response' + name: "server_response" fitables: 25827389e64248f1807a015118509326: aliases: - - 'python_default_server_response' + - "python_default_server_response" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.782eed4bb8ed4867a67d66894719ad09: - name: 'recycle' + name: "recycle" route: - default: '37210e40e78c46beb148a05b99d6fd72' + default: "37210e40e78c46beb148a05b99d6fd72" fit.public.genericables.ea9c023c1c154cc8a72b1f012d828183: route: - default: '98a7e567803c4a4eac0ffd29b4e0a505' + default: "98a7e567803c4a4eac0ffd29b4e0a505" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.f54d01848ca146d7aa450afe77027ddf: - name: 'fit.matata.ruleEngine.rule.json.Execute' + name: "fit.matata.ruleEngine.rule.json.Execute" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: 'f11c6ee7826f4efeab22c0b7675ee1d8' + default: "f11c6ee7826f4efeab22c0b7675ee1d8" fitables: f11c6ee7826f4efeab22c0b7675ee1d8: aliases: - - 'default' + - "default" fit.public.genericables.41151994d1e74245ad1416b75c8eff39: - name: 'fit.matata.tagCenter.tagger.Tag' + name: "fit.matata.tagCenter.tagger.Tag" tags: - - 'nonTraceable' + - "nonTraceable" route: - default: 'aeb64b5c96cf4e68be4b557bf5cde49a' + default: "aeb64b5c96cf4e68be4b557bf5cde49a" fitables: aeb64b5c96cf4e68be4b557bf5cde49a: aliases: - - 'default' + - "default" fit.public.genericables.f770d409efe54555ac7c1ed53efaf1aa: tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.d1a7264b528a41708905463385e0148f: - name: 'notify_fit_service' + name: "notify_fit_service" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.7a896417dc764a7fbb0381bcf128e9ec: - name: 'mq_agent_subscribe' + name: "mq_agent_subscribe" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: MQ_AGENT_SUBSCRIBE_FIT_ID: aliases: - - 'mq_agent_subscribe_python' + - "mq_agent_subscribe_python" fit.public.genericables.9815d4c839e24e038a71b387de2150ea: - name: 'mq_agent_unsubscribe' + name: "mq_agent_unsubscribe" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: MQ_AGENT_UNSUBSCRIBE_FIT_ID: aliases: - - 'mq_agent_unsubscribe_python' + - "mq_agent_unsubscribe_python" fit.public.genericables.bd82ccd28c6047afa85818e835a4c3d7: - name: 'mq_agent_consume' + name: "mq_agent_consume" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fitables: MQ_AGENT_CONSUME_FIT_ID: aliases: - - 'mq_agent_consume_python' + - "mq_agent_consume_python" fit.public.genericables.3788e36a1faf4fed8c50410ebc9bffa8: tags: - - 'nonTraceable' + - "nonTraceable" fitables: FIT_GET_ALL_GLOBAL_CONTEXT_FIT_ID: aliases: - - 'py_impl' + - "py_impl" fit.public.genericables.bc3e4e7d642e4acb8a48fb28cf74376f: tags: - - 'nonTraceable' + - "nonTraceable" fitables: FIT_PUT_GLOBAL_CONTEXT_FIT_ID: aliases: - - 'py_impl' + - "py_impl" fit.public.genericables.327426d21bda4fe58bc6dc7ef726ffa2: tags: - - 'nonTraceable' + - "nonTraceable" fitables: FIT_RESTORE_GLOBAL_CONTEXT_FIT_ID: aliases: - - 'py_impl' + - "py_impl" fit.public.genericables.bfbc3d446c324e0a9ddc2ea55255a168: tags: - - 'nonTraceable' + - "nonTraceable" fitables: FIT_GET_GLOBAL_CONTEXT_FIT_ID: aliases: - - 'py_impl' + - "py_impl" fit.public.genericables.fd3244e74b044cf0af5a43c045601160: tags: - - 'nonTraceable' + - "nonTraceable" fitables: FIT_GET_ALL_ROUTE_CONTEXT_FIT_ID: aliases: - - 'py_impl' + - "py_impl" fit.public.genericables.23e5a8c3e98d4639913799cde09f34ab: tags: - - 'nonTraceable' + - "nonTraceable" fitables: FIT_PUT_ROUTE_CONTEXT_FIT_ID: aliases: - - 'py_impl' + - "py_impl" fit.public.genericables.ce40a173086a4cf795559441cdffd71f: - name: 'is_ready' + name: "is_ready" route: - default: 'e117c6fc9be044b8be7f6273e0a3a55b' + default: "e117c6fc9be044b8be7f6273e0a3a55b" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.ac31756b9122448eae9a701e7691ac55: - name: 'hi' + name: "hi" route: - default: '3ee4572b5aa34b448ec6419ac62715b1' + default: "3ee4572b5aa34b448ec6419ac62715b1" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.1f54daa450848ca1e77027dd46d70aff: - name: 'dynamic_loading_start' + name: "dynamic_loading_start" route: - default: 'd14167424b75c8eff351994d1e5a4119' + default: "d14167424b75c8eff351994d1e5a4119" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.read.meta: - name: 'read_meta_from_big_data_cache' + name: "read_meta_from_big_data_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.create.str: - name: 'create_str_in_big_data_cache' + name: "create_str_in_big_data_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.create.bytes: - name: 'create_bytes_in_big_data_cache' + name: "create_bytes_in_big_data_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.read.str: - name: 'read_str_from_big_data_cache' + name: "read_str_from_big_data_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.read.bytes: - name: 'read_bytes_from_big_data_cache' + name: "read_bytes_from_big_data_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.delete: - name: 'delete_value_in_big_data_cache' + name: "delete_value_in_big_data_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.validate.capacity: - name: 'validate_capacity_in_big_data_cache' + name: "validate_capacity_in_big_data_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.get.info: - name: 'get_info_in_big_data_cache' + name: "get_info_in_big_data_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.bigdata.cache.is_databus: - name: 'get_is_databus_cache' + name: "get_is_databus_cache" route: - default: 'local-worker' + default: "local-worker" tags: - - 'nonTraceable' + - "nonTraceable" fit.public.genericables.modelengine.fit.get.all.plugins.ready: - name: 'modelengine.fit.get.all.plugins.ready' + name: "modelengine.fit.get.all.plugins.ready" fitables: local-worker: route: - default: 'local-worker' + default: "local-worker" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.modelengine.fit.get.running.async.task.count: - name: 'modelengine.fit.get.running.async.task.count' + name: "modelengine.fit.get.running.async.task.count" fitables: local-worker: route: - default: 'local-worker' + default: "local-worker" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.modelengine.fit.get.should.terminate.main: - name: 'modelengine.fit.get.should.terminate.main' + name: "modelengine.fit.get.should.terminate.main" fitables: local-worker: route: - default: 'local-worker' + default: "local-worker" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.modelengine.fit.get.last.success.time: - name: 'modelengine.fit.get.last.success.time' + name: "modelengine.fit.get.last.success.time" fitables: local-worker: route: - default: 'local-worker' + default: "local-worker" tags: - - 'localOnly' - - 'nonTraceable' + - "localOnly" + - "nonTraceable" fit.public.genericables.modelengine.fit.get.earliest.start.time: - name: 'modelengine.fit.get.earliest.start.time' + name: "modelengine.fit.get.earliest.start.time" fitables: local-worker: route: - default: 'local-worker' + default: "local-worker" tags: - - 'localOnly' - - 'nonTraceable' \ No newline at end of file + - "localOnly" + - "nonTraceable" diff --git a/framework/fit/python/fitframework/const.py b/framework/fit/python/fitframework/const.py index d0e19d15..766edf53 100644 --- a/framework/fit/python/fitframework/const.py +++ b/framework/fit/python/fitframework/const.py @@ -161,7 +161,7 @@ GET_FIT_SERVICE_ADDRESS_LIST_GEN_ID = '564286f7db6349b2b29db49feac3b7da' GET_FIT_SERVICE_ADDRESS_LIST_FITABLE_ID = '9602150ac5694585ab9a9e3d7561f48b' -NOTIFY_FIT_SERVICE_GEN_ID = 'b69df5e8cbcd4166aa5029602e7a58cf' +NOTIFY_FIT_SERVICE_GEN_ID = 'modelengine.fit.service.registry-listener.notify-fitables' NOTIFY_FIT_SERVICE_FITABLE_ID = 'NOTIFY_FIT_SERVICE_FITABLE_ID' ONLINE_FIT_SERVICE_GEN_ID = '2ac926e6e40245b78b7bdda23bcb727b' @@ -230,13 +230,13 @@ FIT_CONFIGURATION_SERVER_UPLOAD_FIT_ID = '2ae9d88f46894f7bb0fcd45cf544cb52' # registry server -QUERY_FIT_SERVICE_GEN_ID = '33be4142494e4742aa122555a451d996' -SUBSCRIBE_FIT_SERVICE_GEN_ID = 'c9aa580f3fa845c99c2c6145a0499e45' -REGISTER_FIT_SERVICE_GEN_ID = '85bdce64cf724589b87cb6b6a950999d' -QUERY_FITABLE_METAS_GEN_ID = '7c52fb4fdfa243af928f23607fbbee02' +QUERY_FIT_SERVICE_GEN_ID = 'modelengine.fit.registry.registry-service.query-fitables-addresses' +SUBSCRIBE_FIT_SERVICE_GEN_ID = 'modelengine.fit.registry.registry-service.subscribe-fitables' +REGISTER_FIT_SERVICE_GEN_ID = 'modelengine.fit.registry.registry-service.register-fitables' +QUERY_FITABLE_METAS_GEN_ID = 'modelengine.fit.registry.registry-service.query-running-fitables' # heartbeat server -HEART_BEAT_GEN_ID = 'e12fd1c57fd84f50a673d93d13074082' +HEART_BEAT_GEN_ID = 'modelengine.fit.heartbeat.send-heartbeat' # debugger DEBUGGER_START_FIT_ID = 'debugger_start_fitable_id' diff --git a/framework/fit/python/plugin/fit_py_registry_client/conf/application.yml b/framework/fit/python/plugin/fit_py_registry_client/conf/application.yml index 3c3c7b27..2151c63e 100644 --- a/framework/fit/python/plugin/fit_py_registry_client/conf/application.yml +++ b/framework/fit/python/plugin/fit_py_registry_client/conf/application.yml @@ -1,22 +1,21 @@ registry-center: client: service_id: 2 - mode: 'pull' # pull or push + mode: "pull" # pull or push pull-frequency: 60 registry_fitable_frequency: 15 registered-fitables-expire-interval: 30 # expected expire interval used by server invalid_address_ttl: 60 server: addresses: - - 'localhost:8080' + - "localhost:8080" protocol: 2 formats: - 1 context-path: "" service_ids: - - '85bdce64cf724589b87cb6b6a950999d' - - 'bcad5d59d90b4ee88f195cd7356389fc' - - '33be4142494e4742aa122555a451d996' - - 'c9aa580f3fa845c99c2c6145a0499e45' - - '7c52fb4fdfa243af928f23607fbbee02' - - 'e12fd1c57fd84f50a673d93d13074082' + - "modelengine.fit.registry.registry-service.register-fitables" + - "modelengine.fit.registry.registry-service.query-fitables-addresses" + - "modelengine.fit.registry.registry-service.subscribe-fitables" + - "modelengine.fit.registry.registry-service.query-running-fitables" + - "modelengine.fit.heartbeat.send-heartbeat"