Skip to content

fix: use pluginsvc singleton Instance() across all service and controller constructors#9

Closed
hailaz wants to merge 227 commits into
mainfrom
fix/service-instance-management
Closed

fix: use pluginsvc singleton Instance() across all service and controller constructors#9
hailaz wants to merge 227 commits into
mainfrom
fix/service-instance-management

Conversation

@hailaz

@hailaz hailaz commented May 12, 2026

Copy link
Copy Markdown
Contributor

问题

每个 Controller 和 Middleware 各自调用 pluginsvc.New(nil) 创建独立的 plugin service 实例,导致:

  • 多个 plugin service 实例并存,内存浪费
  • 插件启用/禁用状态的缓存在各实例间不一致
  • 依赖关系不透明,难以排查问题

Closes #6

修改内容

将所有 controller、middleware 及 pkg adapter 中的 pluginsvc.New(nil) 替换为 pluginsvc.Instance() 单例方法,确保所有请求处理路径共享同一个 plugin service 实例。

同时,为 auth.Service 添加 Instance() 单例方法,并对 middleware 中的 auth.New(nil) 同步更新。

涉及文件:

  • internal/controller/auth/auth_new.go
  • internal/controller/menu/menu_new.go
  • internal/controller/role/role_new.go
  • internal/controller/file/file_new.go
  • internal/controller/joblog/joblog_new.go
  • internal/controller/plugin/plugin_new.go
  • internal/service/auth/auth.go
  • internal/service/plugin/plugin.go
  • internal/service/role/role.go
  • internal/service/middleware/middleware.go
  • pkg/sourceupgrade/sourceupgrade.go
  • pkg/pluginservice/session/session.go
  • pkg/pluginservice/auth/auth.go

测试

go build ./... 通过,无编译错误。

gqcn added 30 commits April 16, 2026 15:27
gqcn and others added 18 commits May 11, 2026 16:20
## Summary

- Moves the framework's built-in source-plugin E2E tests
(`content-notice`, `monitor-{loginlog,online,operlog,server}`,
`org-center`) into each plugin's own `hack/tests/{e2e,pages,support}`
directory, completing the source-plugin E2E ownership standard
introduced in #5.
- Introduces `@host-tests/*` and `xlsx` path aliases in
`hack/tests/tsconfig.json` and wires Playwright via the new top-level
`tsconfig` option so plugin-owned tests reference host
fixtures/pages/support through stable aliases instead of 6–7 level
relative paths.
- Updates `hack/tests/config/execution-manifest.json` module scopes,
legacy directory map, and `serialIsolation` for the new plugin-owned
locations; tightens the `e2e/content` reason text to match what remains
under the host tree.
- Updates host i18n regressions `TC0108` / `TC0110` to import
`NoticePage` / `DeptPage` / `PostPage` from the new plugin locations.
- Ticks `FB-3` in `openspec/changes/multi-tenant/tasks.md`.

## Verification

- `pnpm exec tsc --noEmit` (from `hack/tests`)
- `node hack/tests/scripts/validate-e2e.mjs` — 165 files / 30 scopes
- `openspec validate multi-tenant --strict`
- `pnpm test` full suite — **471 pass / 12 skipped / 1 pre-existing
TC-67k 60s timeout**; all 108 plugin-owned tests resolved the
`@host-tests/*` aliases at runtime.

## Test plan

- [x] Type check
- [x] E2E validator
- [x] OpenSpec validator
- [x] Full Playwright suite (parallel + serial)
- [x] Retry of previously-failing TCs confirms 6/7 were environment /
pre-existing flakes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ifications, and scheduled jobs

- Introduced mock data for roles and role bindings to facilitate access control demonstrations.
- Added example configuration parameters for demonstration purposes.
- Included online session records to support session monitoring demos.
- Created inbox notification messages and delivery records for showcasing notification features.
- Established scheduled job groups, jobs, and execution logs to illustrate job management functionalities.
- Updated test to reflect changes in SQL file references for plugin host calls.
…ller constructors

Replace all pluginsvc.New(nil) calls in controllers, middleware, and pkg adapters
with pluginsvc.Instance() to ensure a single shared plugin service instance.
This eliminates duplicate cache states, redundant initialization overhead,
and inconsistent plugin enablement visibility across request handlers.

Affected files:
- internal/controller/auth/auth_new.go
- internal/controller/menu/menu_new.go
- internal/controller/role/role_new.go
- internal/controller/file/file_new.go
- internal/controller/joblog/joblog_new.go
- internal/controller/plugin/plugin_new.go
- internal/service/auth/auth.go
- internal/service/middleware/middleware.go
- pkg/sourceupgrade/sourceupgrade.go
- pkg/pluginservice/session/session.go
- pkg/pluginservice/auth/auth.go
## Summary

End-to-end hardening of the access/refresh token lifecycle across host
backend and Vben frontend. Four commits, all auth-scoped:

- **`fix(auth): prevent logout recursion on expired sessions`** — split
`clearSession` out of `logout`; 401 paths only clear local session
instead of recursing into `/auth/logout`.
- **`fix(auth): refresh access token before reauthentication`** —
introduce host `/auth/refresh` endpoint, JWT `tokenType` claim (`access`
vs `refresh`), refresh token issuance on login/tenant select/tenant
switch, frontend `doRefreshToken` flow. Protected APIs and dynamic
plugin routes now only accept `access` tokens.
- **`refactor(auth): share JWT tokenType literals via pkg/authtoken`** —
extract the `"access"`/`"refresh"` literals into `pkg/authtoken` so the
host signer/parser, dynamic route parser, and multi-tenant impersonation
signer share one source of truth.
- **`fix(auth): harden refresh against tenant eviction and 401 storms`**
- Backend `Refresh` re-validates tenant membership (`bizerr`-coded
denials revoke the session, infra errors keep it so transient DB blips
do not kick users offline) and rejects refresh tokens claiming negative
tenant IDs.
- Frontend refresh queue stores `{resolve, reject}` pairs, rejects them
on refresh failure instead of replaying with an empty token, and drains
again after `doReAuthenticate` so late-arriving 401s do not hang.

## Test plan

- [x] `cd apps/lina-core && go test ./internal/service/auth -count=1` —
covers refresh issuance, tenant flow, tenant eviction
(`TestRefreshRejectsAfterTenantMembershipRemoved`), infra-error
preservation (`TestRefreshPreservesSessionOnTenantProviderInfraError`),
negative-tenant rejection, refresh-token-as-access-token rejection,
revoked-session rejection.
- [x] `cd apps/lina-core && go test
./internal/service/plugin/internal/runtime -run
'Test(ParseDynamicRouteTokenRejectsRefreshToken|DynamicRouteIdentitySnapshotFiltersRolesByTokenTenant|TouchDynamicRouteSessionKeepsExistingSessionWhenTimestampDoesNotChange)$'
-count=1`
- [x] `cd apps/lina-plugins/multi-tenant && go test
./backend/internal/service/impersonate -count=1`
- [x] `cd apps/lina-vben && pnpm -F @vben/request exec vitest run` — 30
/ 30 incl. two new tests (`should reject queued 401 requests when
refresh fails`, `should not hang requests that 401 during the
doReAuthenticate window`).
- [x] `cd apps/lina-vben && pnpm -F @lina/web-antd typecheck`
- [x] `cd hack/tests && pnpm exec playwright test
e2e/auth/TC0233-expired-session-logout-loop.ts --project=chromium` —
TC0233a (no logout storm on stale token) and TC0233b (refresh-then-retry
path) both pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This pull request addresses several maintenance issues in the CI/CD
pipeline and refines the SQLite SQL translator's handling of PostgreSQL
comment statements. The most important changes include updating GitHub
Actions workflows to resolve deprecation warnings, switching to more
robust action versions, and removing unnecessary debug logging from the
SQLite translator and its tests.

**GitHub Actions maintenance and warning cleanup:**

* Upgraded `actions/setup-go` from `v5` to `v6` and `pnpm/action-setup`
from `v4` to `v6` across all workflows for improved compatibility and to
resolve deprecation warnings.
[[1]](diffhunk://#diff-993609d1e993acb4eeef79ed9dad54194b6c9ed15a9eab32f08405c0339cf272L49-R60)
[[2]](diffhunk://#diff-2ee59052448a421cff47b6ee98f786b57f3012d9f9132d37b9bde685a6266166L39-R45)
[[3]](diffhunk://#diff-3c029feaffecba973036636cbec5eaec24fa02f80b3fbd62960738255238e4f7L57-R71)
[[4]](diffhunk://#diff-52120b4145bd2cf9c735193f6a093a7944688b21f04e854447e34a5049fc829fL38-R44)
[[5]](diffhunk://#diff-892add1f02013bfef6bfe38c6082b48f1957f125ab4716cf22424f137b8754dfL37-R48)
[[6]](diffhunk://#diff-d38ce4cdc17f4173ce027ea199206522ca308703265f7380bf866a145bf8a8f5L21-R29)
[[7]](diffhunk://#diff-d1f987969ebd72f880efb0c738249eacdfc531b95d073bf26a3c3a406f58bd6aL13-R24)
* Replaced the deprecated `szenius/set-timezone@v2.0` action with native
shell commands to set the timezone on Ubuntu runners, eliminating the
dependency on Node.js 20 actions.
[[1]](diffhunk://#diff-993609d1e993acb4eeef79ed9dad54194b6c9ed15a9eab32f08405c0339cf272L49-R60)
[[2]](diffhunk://#diff-3c029feaffecba973036636cbec5eaec24fa02f80b3fbd62960738255238e4f7L57-R71)
[[3]](diffhunk://#diff-892add1f02013bfef6bfe38c6082b48f1957f125ab4716cf22424f137b8754dfL37-R48)
[[4]](diffhunk://#diff-d38ce4cdc17f4173ce027ea199206522ca308703265f7380bf866a145bf8a8f5L21-R29)
* Explicitly disabled Go toolchain/module cache in `actions/setup-go` to
avoid cache restore tar failure warnings.
[[1]](diffhunk://#diff-993609d1e993acb4eeef79ed9dad54194b6c9ed15a9eab32f08405c0339cf272L49-R60)
[[2]](diffhunk://#diff-2ee59052448a421cff47b6ee98f786b57f3012d9f9132d37b9bde685a6266166L39-R45)
[[3]](diffhunk://#diff-3c029feaffecba973036636cbec5eaec24fa02f80b3fbd62960738255238e4f7L57-R71)
[[4]](diffhunk://#diff-52120b4145bd2cf9c735193f6a093a7944688b21f04e854447e34a5049fc829fL38-R44)
[[5]](diffhunk://#diff-892add1f02013bfef6bfe38c6082b48f1957f125ab4716cf22424f137b8754dfL37-R48)
[[6]](diffhunk://#diff-d1f987969ebd72f880efb0c738249eacdfc531b95d073bf26a3c3a406f58bd6aL13-R24)
* Updated the Windows runner label from `windows-latest` to
`windows-2025-vs2026` to address platform redirection warnings.

**SQLite SQL translator and test refinement:**

* Removed unnecessary debug logging when skipping PostgreSQL comment
statements in the SQLite translator, making the translation process
silent for these cases.
* Simplified and parallelized the related unit test by removing global
logger handler hooks and log content assertions, ensuring tests remain
self-contained and robust.
[[1]](diffhunk://#diff-67f40cae72d449c63af47f51a614877a6143c01439ed001cc59d9aa67009bee3L9-L12)
[[2]](diffhunk://#diff-67f40cae72d449c63af47f51a614877a6143c01439ed001cc59d9aa67009bee3L227-R228)
[[3]](diffhunk://#diff-67f40cae72d449c63af47f51a614877a6143c01439ed001cc59d9aa67009bee3L246-R243)
[[4]](diffhunk://#diff-67f40cae72d449c63af47f51a614877a6143c01439ed001cc59d9aa67009bee3L276-L287)
[[5]](diffhunk://#diff-67f40cae72d449c63af47f51a614877a6143c01439ed001cc59d9aa67009bee3L320-L329)

**Documentation and OpenSpec updates:**

* Updated OpenSpec task records to reflect all the above changes,
including validation commands and the rationale for each fix.
@gqcn

gqcn commented May 12, 2026

Copy link
Copy Markdown
Contributor

@hailaz 只实现了plugin的单例,预计需要将所有的接口实现都做单例处理,我来处理下。

@hailaz hailaz marked this pull request as draft May 12, 2026 07:03
@hailaz hailaz marked this pull request as draft May 12, 2026 07:03
hailaz added 5 commits May 12, 2026 15:32
… pattern

- Add Instance() singleton access for 6 core services: auth, role, tenantcap, session, orgcap, config
- Replace New() calls with Instance() across all service implementations
- Add missing type definitions: usermsgI18nTranslator, apidocI18nService, Snapshot, Item
- Fix locker package naming conflict: rename Instance struct to LockInstance
- Fix various compilation errors in startupstats, kvcache, scheduler, and other packages
- Update all controllers to use Instance() pattern
- Mark New() functions as Deprecated in favor of Instance()
- Add .codebuddy/plan/ to .gitignore
…singleton

- kvcache.Item: rename field Kind back to ValueKind to keep callers compiling
  (auth tests, sqltable_ops, hostfn_service_cache, hostservice cache codec all
  consume Item.ValueKind).
- locker: rename type LockInstance back to Instance to preserve the original
  domain naming; drop the locker.Instance() singleton entry and the unused
  sync.Once wiring, since locker holds per-acquisition state and must be
  constructed via locker.New() by each caller (cluster.electionSvc,
  hostlock.lockerSvc).
- cluster.electionService: follow the type rename (*locker.LockInstance ->
  *locker.Instance).

Eliminates the three [build failed] regressions on this branch (kvcache,
locker, auth) without touching the wider singleton scope, leaving that
discussion to a separate change.
@gqcn gqcn closed this May 18, 2026
@hailaz hailaz deleted the fix/service-instance-management branch May 21, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

潜在问题分析

4 participants