mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-01 14:19:40 +08:00
fix(server): indexer feature (#15533)
<!-- Thank you for contributing to AFFiNE! The PR title must follow Conventional Commits (enforced by CI): type(scope): description e.g. fix(editor): keep selection after paste Types: feat fix docs style refactor perf test build ci chore revert --> ## Description <!-- What does this PR do? Link related issues, e.g. "Closes #1234". Screenshots or recordings are welcome for UI changes. --> ## Checklist - [ ] I have signed the [AFFiNE Contributor License Agreement](https://cla-assistant.io/toeverything/AFFiNE) — required before merge; the `license/cla` check must be green ([how it works](https://github.com/toeverything/AFFiNE/blob/canary/docs/BUILDING.md#sign-the-cla-first)) - [ ] The PR targets the `canary` branch and its title follows [Conventional Commits](https://www.conventionalcommits.org/) - [ ] Tests are added or updated where it makes sense - [ ] `yarn lint` and `yarn typecheck` pass locally #### PR Dependency Tree * **PR #15533** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved indexer feature synchronization when the indexer is enabled or configuration changes. * Enabled indexer-related capabilities without waiting for native search readiness checks. * Improved consistency across search, aggregate, document, and application startup flows. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,27 +1,18 @@
|
||||
import { serverConfigQuery, ServerFeature } from '@affine/graphql';
|
||||
|
||||
import { Config } from '../../../base';
|
||||
import { BackendRuntimeProvider } from '../../../core/backend-runtime';
|
||||
import { IndexerService } from '../../../plugins/indexer';
|
||||
import { app, e2e } from '../test';
|
||||
|
||||
e2e(
|
||||
'should expose the indexer feature when its projection is ready',
|
||||
async t => {
|
||||
const enabled = app.get(Config).indexer.enabled;
|
||||
if (enabled) {
|
||||
await app.get(BackendRuntimeProvider).reconcileSearchProjection(1000);
|
||||
await app.get(IndexerService).onApplicationBootstrap();
|
||||
}
|
||||
const { serverConfig } = await app.gql({ query: serverConfigQuery });
|
||||
e2e('should expose the indexer feature when it is enabled', async t => {
|
||||
const enabled = app.get(Config).indexer.enabled;
|
||||
const { serverConfig } = await app.gql({ query: serverConfigQuery });
|
||||
|
||||
t.is(
|
||||
serverConfig.features.includes(ServerFeature.Indexer),
|
||||
enabled,
|
||||
JSON.stringify(serverConfig, null, 2)
|
||||
);
|
||||
}
|
||||
);
|
||||
t.is(
|
||||
serverConfig.features.includes(ServerFeature.Indexer),
|
||||
enabled,
|
||||
JSON.stringify(serverConfig, null, 2)
|
||||
);
|
||||
});
|
||||
|
||||
e2e('should comment feature enabled by default', async t => {
|
||||
const { serverConfig } = await app.gql({ query: serverConfigQuery });
|
||||
|
||||
@@ -31,7 +31,7 @@ function enabledServer() {
|
||||
};
|
||||
}
|
||||
|
||||
test('reflects native search readiness in the Node feature flag', async t => {
|
||||
test('exposes the indexer capability while its projection is building', async t => {
|
||||
const runtime = {
|
||||
searchStatus: Sinon.stub(),
|
||||
searchAuthorized: Sinon.stub().resolves({
|
||||
@@ -39,9 +39,6 @@ test('reflects native search readiness in the Node feature flag', async t => {
|
||||
value: { total: 0, nodes: [] },
|
||||
}),
|
||||
};
|
||||
runtime.searchStatus.onFirstCall().resolves({ ready: true });
|
||||
runtime.searchStatus.onSecondCall().resolves({ ready: false });
|
||||
runtime.searchStatus.onThirdCall().resolves({ ready: true });
|
||||
const server = enabledServer();
|
||||
const service = new IndexerService(
|
||||
runtime as unknown as BackendRuntimeProvider,
|
||||
@@ -53,9 +50,9 @@ test('reflects native search readiness in the Node feature flag', async t => {
|
||||
await service.onConfigChanged({ updates: { indexer: {} } } as never);
|
||||
await service.search('actor', 'workspace', {} as never);
|
||||
|
||||
t.is(server.enableFeature.callCount, 2);
|
||||
t.true(server.disableFeature.calledOnce);
|
||||
t.is(runtime.searchStatus.callCount, 3);
|
||||
t.is(server.enableFeature.callCount, 3);
|
||||
t.false(server.disableFeature.called);
|
||||
t.false(runtime.searchStatus.called);
|
||||
});
|
||||
|
||||
test('does not query native search when the indexer is disabled', async t => {
|
||||
|
||||
@@ -45,26 +45,24 @@ export class IndexerService implements OnApplicationBootstrap {
|
||||
) {}
|
||||
|
||||
async onApplicationBootstrap() {
|
||||
await this.syncFeature();
|
||||
this.syncFeature();
|
||||
}
|
||||
|
||||
@OnEvent('config.changed.broadcast')
|
||||
async onConfigChanged({ updates }: Events['config.changed.broadcast']) {
|
||||
if (updates.indexer) await this.syncFeature();
|
||||
if (updates.indexer) this.syncFeature();
|
||||
}
|
||||
|
||||
private async syncFeature() {
|
||||
if (!this.server.getConfig().indexer.enabled) {
|
||||
private syncFeature() {
|
||||
if (this.server.getConfig().indexer.enabled) {
|
||||
this.server.enableFeature(ServerFeature.Indexer);
|
||||
} else {
|
||||
this.server.disableFeature(ServerFeature.Indexer);
|
||||
return;
|
||||
}
|
||||
const status = (await this.runtime.searchStatus()) as { ready: boolean };
|
||||
if (status.ready) this.server.enableFeature(ServerFeature.Indexer);
|
||||
else this.server.disableFeature(ServerFeature.Indexer);
|
||||
}
|
||||
|
||||
async search(actorUserId: string, workspaceId: string, input: SearchInput) {
|
||||
await this.syncFeature();
|
||||
this.syncFeature();
|
||||
const result = this.unwrap<SearchResult>(
|
||||
await this.runtime.searchAuthorized(actorUserId, workspaceId, input),
|
||||
workspaceId
|
||||
@@ -77,7 +75,7 @@ export class IndexerService implements OnApplicationBootstrap {
|
||||
workspaceId: string,
|
||||
input: AggregateInput
|
||||
) {
|
||||
await this.syncFeature();
|
||||
this.syncFeature();
|
||||
const result = this.unwrap<AggregateResult>(
|
||||
await this.runtime.aggregateAuthorized(actorUserId, workspaceId, input),
|
||||
workspaceId
|
||||
@@ -104,7 +102,7 @@ export class IndexerService implements OnApplicationBootstrap {
|
||||
keyword: string,
|
||||
options?: { limit?: number; docIds?: string[] }
|
||||
): Promise<SearchDoc[]> {
|
||||
await this.syncFeature();
|
||||
this.syncFeature();
|
||||
if (options?.limit !== undefined && options.limit <= 0) {
|
||||
throw new InvalidIndexerInput({
|
||||
reason: 'searchDocs limit must be positive',
|
||||
|
||||
Reference in New Issue
Block a user