Skip to content

feat: Add custom client class support - #4587

Merged
czy88840616 merged 3 commits into
midwayjs:v4-nextfrom
itmajing:feat/custom-client-support
Jun 13, 2026
Merged

feat: Add custom client class support#4587
czy88840616 merged 3 commits into
midwayjs:v4-nextfrom
itmajing:feat/custom-client-support

Conversation

@itmajing

@itmajing itmajing commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
Checklist
  • npm test passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

不影响,完全兼容

Description of change

支持自定义客户端扩展
#4586

@czy88840616 czy88840616 added the pr: polish This PR adds a very minor behavior improvement that users will enjoy. label Jun 7, 2026
@codecov-commenter

codecov-commenter commented Jun 7, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 69.51220% with 25 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (v4-next@36fadb0). Learn more about missing BASE report.

Files with missing lines Patch % Lines
packages/redis/src/manager.ts 41.02% 23 Missing ⚠️
packages/cos/src/manager.ts 85.71% 0 Missing and 1 partial ⚠️
packages/oss/src/manager.ts 85.71% 0 Missing and 1 partial ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##             v4-next    #4587   +/-   ##
==========================================
  Coverage           ?   85.63%           
==========================================
  Files              ?      643           
  Lines              ?    66673           
  Branches           ?     8081           
==========================================
  Hits               ?    57095           
  Misses             ?     9516           
  Partials           ?       62           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@czy88840616 czy88840616 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. The direction is useful, but I think this needs to be narrowed and aligned before merge.

  1. customClientClass is used in Redis/OSS/COS/Consul/ETCD/Sequelize, but the public config types are not updated.

ServiceFactoryConfigOption still only types default / client / clients values as PowerPartial<OPTIONS>, and DataSourceManagerConfigOption only exposes customDataSourceClass. In a normal TypeScript config, users cannot add customClientClass cleanly without casts, so the feature is effectively untyped.

  1. Sequelize should not introduce a separate customClientClass API.

Sequelize is a DataSourceManager component like TypeORM. Core already has customDataSourceClass, and TypeORM uses that name. If Sequelize adds customClientClass, then customDataSourceClass is silently ignored for Sequelize while the new field is not part of the DataSourceManager config type. This creates an unnecessary inconsistency between ORM components.

I suggest changing Sequelize to use customDataSourceClass and adding tests for it.

  1. The PR currently applies the same extension to OSS/COS/Consul/ETCD, but the compatible-client contract is unclear.

For vendor-SDK wrapper components like OSS/COS, there may not be a real compatible replacement client. A custom class can also bypass or break assumptions around proxy methods, trace wrapping, and lifecycle behavior. Based on the discussion, I suggest narrowing this PR first to components where the abstraction is clear, such as Sequelize and possibly Redis.

For Redis, please make the supported contract explicit, for example “an ioredis-compatible subclass/wrapper”, and add tests covering normal client creation, ready / error handling, trace binding, and injected service proxy behavior.

Overall recommended scope for this PR:

  • Sequelize: support customDataSourceClass, matching TypeORM.
  • Redis: only if the custom client is explicitly ioredis-compatible, with tests and config typing.
  • Defer OSS/COS/Consul/ETCD unless there is a concrete compatible-client use case and tests for trace/lifecycle behavior.

@czy88840616

Copy link
Copy Markdown
Member

补充一下,上一条 review 里第 3 点我表述得不准确,收回“不建议扩 OSS/COS/Consul/ETCD”这个判断。既然已经有企业内部扩展诉求,这些 vendor SDK wrapper 组件也可以继续做扩展支持。

我这边建议本 PR 重点调整为:

  1. 补齐公开配置类型。

现在代码里读取了 customClientClass,但 ServiceFactoryConfigOption 还没有这个字段;使用 TS 写配置时用户会遇到类型不匹配。建议在 core 的通用 ServiceFactory 配置类型里补上,而不是各组件里 as any

  1. Sequelize 建议和 TypeORM 保持 API 命名一致。

Sequelize 和 TypeORM 一样走 DataSourceManager,core 里已经有 customDataSourceClass,TypeORM 也是这个字段。这里如果新增 customClientClass,会导致 ORM 组件之间 API 不一致,也会让 customDataSourceClass 在 Sequelize 里无效。建议 Sequelize 改成支持 customDataSourceClass

  1. Redis / OSS / COS / Consul / ETCD 可以继续支持 customClientClass,但需要补测试。

至少覆盖:

  • 单 client / 多 clients 配置下能创建自定义 client;
  • customClientClass 不会继续透传给底层 SDK 构造函数;
  • 原有 trace 包装仍然生效;
  • 原有 service/factory 注入方式不变;
  • Redis 额外覆盖 ready / error 生命周期,避免自定义 client 后启动流程卡住或错误处理失效。

整体上我主要 concern 是类型和一致性,不是反对这些组件做扩展。

@itmajing

Copy link
Copy Markdown
Contributor Author

感谢反馈!已按要求调整:

  • 补齐了公开配置类型;
  • Sequelize 改用 customDataSourceClass;
  • 补充了测试;

另外 createClient 内部暂时保留了 as any,为了不做特别大的代码调整。请再帮忙看看是否还有其他问题?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds opt-in support for supplying a custom client/data-source class via configuration, allowing Midway’s various ServiceFactory/DataSourceManager-based integrations (Redis/OSS/ETCD/COS/Consul/Sequelize) to instantiate user-provided client implementations while keeping existing factory/service injection and trace-context binding behavior.

Changes:

  • Add customClientClass to ServiceFactoryConfigOption typing (core) and implement custom instantiation in multiple package managers.
  • Add customDataSourceClass instantiation support in Sequelize data source manager.
  • Add test suites validating custom client/data source creation, config merge behavior, and trace binding.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/sequelize/src/dataSourceManager.ts Instantiate Sequelize via customDataSourceClass when provided.
packages/sequelize/test/customDataSource.test.ts Tests for custom Sequelize data source creation and merged config behavior.
packages/redis/src/manager.ts Support customClientClass for Redis client creation.
packages/redis/test/customClient.test.ts Tests for custom Redis clients, injection, error propagation, and tracing.
packages/oss/src/manager.ts Support customClientClass for OSS client creation (with trace binding).
packages/oss/test/customClient.test.ts Tests for custom OSS clients and tracing.
packages/etcd/src/manager.ts Support customClientClass for ETCD client creation (with trace binding).
packages/etcd/test/customClient.test.ts Tests for custom ETCD clients and tracing.
packages/cos/src/manager.ts Support customClientClass for COS client creation (with trace binding).
packages/cos/test/customClient.test.ts Tests for custom COS clients and tracing.
packages/consul/src/manager.ts Support customClientClass for Consul client creation (with trace binding).
packages/consul/test/customClient.test.ts Tests for custom Consul clients, config merge, and tracing.
packages/core/src/interface.ts Extend ServiceFactoryConfigOption to allow customClientClass.
packages/core/test/common/serviceFactory.test.ts Type-level test ensuring customClientClass is accepted by config option types.
Comments suppressed due to low confidence (1)

packages/redis/src/manager.ts:103

  • When using customClientClass, this code assumes the created client implements EventEmitter semantics (on('ready')/on('error')). If a custom client doesn't expose on (or if it is already in ready state and emitted ready synchronously in its constructor), app startup will throw a confusing client.on is not a function error or hang forever waiting for ready. Consider validating the interface and short-circuiting when the client is already ready to make the new extension point safer.
    await new Promise<void>((resolve, reject) => {
      client.on('ready', () => {
        this.logger.info(`[midway:redis] client(${name}) connect success`);
        resolve();
      });

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 59 to 61
async createClient(
config: OSSServiceFactoryCreateClientConfigType
): Promise<T> {
@@ -42,6 +42,13 @@ export class ETCDServiceFactory extends ServiceFactory<Etcd3> {
protected traceInjector;

async createClient(config: IOptions): Promise<Etcd3> {
@@ -43,6 +43,13 @@ export class COSServiceFactory extends ServiceFactory<COS> {
protected traceInjector;

async createClient(config: COS.COSOptions): Promise<COS> {
Comment on lines 44 to 47
async createClient(
config: ConsulOptions,
clientName: string
): Promise<InstanceType<typeof Consul>> {
@czy88840616
czy88840616 merged commit 3d77df5 into midwayjs:v4-next Jun 13, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr: polish This PR adds a very minor behavior improvement that users will enjoy.

Development

Successfully merging this pull request may close these issues.

4 participants